1. 程式人生 > >登入註冊密文傳輸密碼

登入註冊密文傳輸密碼

如何保證使用者登入時提交密碼已經加密?

其實在接收到了之後再加密是非常方便的,你可以在後臺輕鬆做各種加密,這樣幾乎可以保證資料拿去也變不成明文內容。但問題是在傳輸的時候,假設我們不使用 https,即使是使用 https 傳輸,如何保證使用者的資料被提交過來的時候是已經加密過的?

現在有一種方法是用 js 加密。比如:JS_MD5('origiPassword')。但問題是我們還要保證功能的可用性。比如無 JS 環境用 form 也可以提交。假設是註冊使用者。這時無 JS 的情況傳輸到後臺的時候是明文密碼,那麼存在資料庫的時候可能是這樣的 salt + md5(origiPassword, salt),但當用戶下次登入的時候是在有 JS 的環境裡,那麼,去資料庫校驗的就會因為不符而登入不上,所以如題?有什麼比較好的方法? 如何保證使用者登陸時提交密碼已經加密?密碼是否已加密,需要客戶端和服務端建立約定,雙方按約定辦事就行了。


這裡提到的另一個問題是,如何保證傳輸安全?
最理想的方案當然是走 HTTPS 協議. HTTPS 在理論上是可靠的,但在國內會打一些折扣:你可以隨便找一臺電腦看看有沒有安裝商業公司或機構的根證書,這些根證書為線路某節點成為中間人提供了可能性;同時,在木馬橫行的年代,密碼在加密提交前可能就被拿到了,此時 HTTPS 成了擺設,這是為什麼國內流行密碼控制元件的一個重要原因。

從成本和需求上考慮,對於眾多對安全性要求不高的個人網站,仍然可以考慮採用 HTTP 傳輸,密碼提交前通過 JavaScript 加密。由於 JavaScript 程式碼暴露在客戶端,因此一般通過不可逆的加密方法加密密碼,而對於任何摘要式的加密演算法,都可以通過類似 md5 字典的方式直接查表獲知弱密碼,所以要混入 salt 以增加製作字典的成本。可想而知,解密只是時間成本的問題。因此這裡的重要前提是“對安全性要求不高”。


如何驗證密碼呢?一個可行的方法是,客戶端提交 md5(password) 密碼(如上所述,此方法只是簡單保護了密碼,是可能被查表獲取密碼的)。服務端資料庫通過 md5(salt+md5(password)) 的規則儲存密碼,該 salt 僅儲存在服務端,且在每次儲存密碼時都隨機生成。這樣即使被拖庫,製作字典的成本也非常高。
密碼被 md5() 提交到服務端之後,可通過 md5(salt + form['password']) 與資料庫密碼比對。此方法可以在避免明文儲存密碼的前提下,實現密碼加密提交與驗證。
這裡還有防止 replay 攻擊(請求被重新發出一次即可能通過驗證)的問題,由服務端頒發並驗證一個帶有時間戳的可信 token (或一次性的)即可。

當然,傳輸過程再有 HTTPS 加持那就更好了。

最後,為什麼要密碼控制元件?原因之一是上面說的,要防止密碼在提交前被截獲。當然,還有一些其他原因,工作所限,這裡就不說了。

以下是光神的講解:

中間人攻擊(Man-in-the-Middle Attack, MITM)是一種由來已久的網路入侵手段,並且在今天仍然有著廣泛的發展空間,如SMB會話劫持、DNS欺騙等攻擊都是典型的MITM攻擊。簡而言之,所謂的MITM攻擊就是通過攔截正常的網路通訊資料,並進行資料篡改和嗅探,而通訊的雙方卻毫不知情。

彩虹表就是一個龐大的、針對各種可能的字母組合預先計算好的雜湊值的集合,不一定是針對MD5演算法的,各種演算法的都有,有了它可以快速的破解各類密碼。越是複雜的密碼,需要的彩虹表就越大,現在主流的彩虹表都是100G以上。

該 salt 僅儲存在服務端,且在每次儲存密碼時都隨機生成。稍微看過幾個開源程式的密碼驗證部分就能看出來了。有的是一個password欄位一個salt欄位,有的為了相容,就是password:salt這樣儲存,但被拖庫的時候,一可以扛彩虹表,二可以拖慢暴力破解速度,其中尤其以扛彩虹表為關鍵。

 彩虹表和暴力破解是不同的,我們講暴力破解,一般是詞典/遍歷攻擊,彩虹表,是直接查表。彩虹表一般是O(1)的時間,暴力不一定。  例如一句
aquickbrownfoxjumpsoverthelazydog
很有可能彩虹表沒存這一句
但詞典,把
a quick brown fox jumps over the lazy dog
都存下來了
然後組合出這個組合,進行嘗試