如何保證用戶登錄時提交密碼已經加密?

其實在接收到了之後再加密是非常方便的,你可以在後台輕鬆做各種加密,這樣幾乎可以保證數據拿去也變不成明文內容。但問題是在傳輸的時候,假設我們不使用 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 加持那就更好了。

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

謝謝邀請。


用https就好了,如果傳輸的過程中(而不是到了伺服器之後才)被破解,那這個鍋就是別人的,你不用負責(逃

題主的第二段不知道在說什麼,這個事情跟JS並沒有關係。而且就算你加了鹽,防的也只是彩虹表。一個計算流程的任何環節都可以被攻擊,如果你的伺服器程序本身被爆了,那也沒有用。

假設你的伺服器程序和操作系統沒有漏洞,那你只需要裝bitlocker就好了,因為人家拿走硬碟也什麼都看不到,除非他是機房管理員。

相比之下,程序本身的漏洞更可怕,天知道你因為什麼操作一不小心邏輯出了問題就泄露秘密了,就像知乎的匿名用戶一樣,隨便爆。


用js在表單中加一個隱藏欄位來標識是否加密密碼


使用js和後端的代碼做非對稱加解密,這裡是個參考 http://www-cs-students.stanford.edu/~tjw/jsbn ,其實原理和https一樣。不是所有伺服器環境都支持https,所以可酌情考慮使用。


為什麼大家都這麼喜歡用md5加密,md5根本不是一個加密演算法,只是一個hash演算法,加密存儲應該用其他演算法,這就是為什麼被爆庫之後這麼容易還原明文。
參考:
How To Safely Store A Password


https


加密的本質是對原有內容的混淆,目的是提高從表面結果反推達到目的的成本。
在網頁提交(其實所有的通信都有這個問題)密碼這個問題上,需要有幾個維度來保證安全,首先是切面的安全性,對於一次提交首先保護的是密碼本身,從最早的Base64到MD5或是SHA都可以做到這一點,但是Base64是可逆的,對於密碼本身的保護是很弱的,哈希演算法解決了這個問題,將不同長度的數據轉換成統一長度的大數字,而理論上這個數字對應無窮多解,但限於密碼的輸入有限制,其實是可逆的,所以從1次混淆的MD5變成了3次混淆的SHA,但是隨著現代計算機技術的進步,逆運算的成本不斷降低,人們不得已要使用更大的數字來提高這個難度,但是為了向成本和發展妥協,人們不得已使用統一的演算法,在CS時代由於很難侵入到CS兩端,所以相對的雙方使用的演算法是保密的,破解難度相對比較大,BS由於為了保證開放性,特別是js本身就是明文演算法,所以其實只能說防君子不妨小人,所以就有了安全控制項,控制項的唯一目的是用2進位代碼來隱藏加密的演算法,不知道演算法,也就很難破解原文。
第二維度就是時間,如果密碼一樣加密結果也會一樣,那麼在不使用原文的情況下,可以使用加密過後的數據來模擬用戶登錄的動作也是可以的,所以純粹對密碼的加密其實不能解決這個問題,所以有了鹽值,讓同一個數據在不同情況下結果依舊不一致,但是鹽值需要約定,總會被人找出規律,只是成本又高了點,所以還是不安全,這就引發了通訊安全的問題。
所以出現了https使用非對稱加密來保護數據通路上的安全,讓通訊變得不可窺視。
但是還有個東西叫木馬,所以人們在輸入上繼續做文章,包括混淆輸入,就是軟鍵盤,好的控制項不會把明文存在內存里,這很重要,以前的VB、Dephi密碼控制項都僅僅看不到,實際內存裡面都是明文,很容易被病毒和木馬利用,所以一般來說現在最安全的bs系統使用控制項保護輸入,隱藏自己的HASH演算法,用HTTPS保護通訊。
但是ssl都有漏洞被爆出,所以好的系統加上用戶自己勤換密碼才是保護自己的不二法則,不過,太累了,所以使用硬體ukey吧,成本稍高


登錄這種場景,不用HTTPS絕對是天理不容,沒有借口


https是最佳解。js md5即使加密了,http傳輸中的header、cookie等其他表單信息都還是明文,還不如直接用https來的省事。畢竟將來大方向就是去http,現在所有的http/2實現都必須基於https了。


js加密,只要知道網站的js源代碼,便存在被破解的可能性。
http提交的數據,有可能被抓包後找到加密後的密碼,別人可以利用這個加密後的密文來偽造一次登錄請求,這也是一樣不安全的,對方只需要保留這個密文即可,不需要知道原始內容。
https不說了,成本高。

個人贊同 @janlay 提到的一次性token方式。我考慮的方案是:
瀏覽器打開頁面時,伺服器生成一個token,返回給客戶端,客戶端登錄時,還是要加密,當然是包含該token來加密,然後返回給伺服器,伺服器解密驗證,同時token失效以保證請求不會被replay登錄,然後伺服器生成session id返回給客戶端,後面在瀏覽進程中以session id來判斷用戶。
客戶端的加密,即使不可逆,如果每次加密後都是一樣內容,那等於沒加密,加入伺服器提供的臨時token來保證加密結果每次都不一樣。
伺服器接收到請求後,取用戶註冊時使用的密碼密文跟臨時token加密後進行比對。
臨時token的生成,可以混入請求IP、時間戳、用戶代理(userAgent)。

以上僅個人假設的方案,未實施過,僅供參考,http的傳輸,太不安全。


先說結論:https已經基本上滿足場景需求了,沒必要搞一堆web客戶端加密的操作。

在web端加密密碼沒什麼太大的作用,因為你還要交換加密用的密碼,除非用你用非對稱加密,電腦里的公鑰私鑰或者usbkey這樣的密鑰來進行簽名和加密。

簽名是用來證明密碼是你提交的,加密是讓別人截獲了通信也看不到內容。

然而,現在chrome和firefox都對http頁面的有password的表單做了警告。就是要提醒大家淘汰掉http的網站,切換到https去。

最佳實踐就是:全站https,包括cdn回源也https。

當然,如果覺得自己部署了https,瀏覽器也有小綠標了就萬事大吉了的話。那麼,其實存在很多潛在的風險因素。

那麼請點開以下鏈接比較一下報告的內容差異。

https://myssl.com/myssl.com

https://myssl.com/t2.baidu.com

https://myssl.com/youhuilife.com

https://myssl.com/www.quqianbao.com


關鍵詞:HTTPS安全最佳實踐。


先回答樓主的問題:一般salt是和密碼一起存在伺服器端的,明文密碼的話伺服器端自己加salt。如果前端加salt,由於這個salt是固定的,那麼需要把salt先發給前端,讓前端算好hash以後再po回到伺服器端直接驗證。但是這樣導致前後端會增加一個來回,就是通過登錄ID把salt發給前端這個過程。

看到有說簡化的方法,即,後端使用md5(salt+md5(pwd)),這樣可以前端不用salt,只發送md5(pwd)。但是這樣和明文其實沒有區別,不推薦。

另外看你的演算法是salt+md5(salt+md5(pwd))。最外層的salt沒有必要加,因為一般salt都是固定長度。

你可以參考一下微信公眾號開發時的簽名演算法。是在客戶端產生一個時間戳salt,然後混入所有關鍵信息後,做sha1的hash,再把salt/hash/id一起發給服務端驗證。具體你查一下官網的文檔。與此類似,把驗證碼當salt也是可行的。

另外我記得discuz曾使用一種可逆的加解密演算法,這種演算法只能通過伺服器端的私鑰解密,你可以搜索參考一下。

最後說一下在回復中看到的問題。

md5/hash,都是摘要,不可逆,所以我前面一直說破解,而不是解密,也就是有可能有hash相同但明文不同的情況,但是幾率很低。

暴力破解對一切加密都有效,所以只有更好的加密,沒有最好的。提升加密強度的過程只是一個增加破解成本的過程,破解成本只要高於被加密對象的價值,我認為就是有效的加密。

關於前端安全,md5/sha1的演算法都是公開的,也沒見靠演算法破解的。只要前端不存明文,一般就沒什麼問題。標準瀏覽器對cockie等隱私文件的域控制已經很完善了,而且瀏覽器都是BS結構,怎麼可能BB抓取呢?看到很多人吐槽前端安全,我不太理解。我倒是前幾天看了個新聞,說有個黑客在某有關部門附近黑進了人家的Wi-Fi,通過抓包把人家的辦公密碼都收集全了。這種情況,首先是不改在辦公環境里使用Wi-Fi網路,這是非技術因素降低了破解成本。其次,說明前端po的都是明文或者md5密碼,但這和前端代碼安全無關,這是程序設計的問題,cs結構也一樣。

最後說一下伺服器被爆竊的問題。首先是伺服器被攻破,其次資料庫被攻破。我覺得首先這跟樓主問題無關,其次這不是md5的錯。

一沒留神說了這麼多。祝你儘快找到合適的安全的加密方式,並用上https

---

剛解決了js使用rsa公鑰加密信息、伺服器端私鑰解密信息的問題。伺服器用salt+md5存儲密碼,客戶端發送rsa的加密登錄信息,個人感覺OK了。


說https足夠的人,都是不懂安全的。
——
我們是使用後台的加密機器,在提交密碼會先用加密機生成兩個 RSA 公鑰,以及一個時間戳,一個傳輸加密密鑰Tek,一個密碼加密密鑰Kek,用密碼加密密鑰對密碼的MD5加密,然後用RC4-MD5對稱加密的方式,加密密碼,然後用傳輸加密密鑰,對剛才RC4-MD4的傳輸密碼加密。最後通過https協議將兩個加密後的結果傳輸過去。
——
我知道你沒聽懂,你要做的話,可以簡化一下,從伺服器拉取一個RSA公鑰,然後加密傳過去,可以防止https中間人攻擊,哪怕信任了黑客的根證書也沒事。


客戶端永不可信任,基於此上述方案行不通。


先說結論:使用HTTPS,伺服器端加鹽後hash存儲

1.HTTPS在傳輸層提供了加密,應用層被包裹其中。故將明文密碼通過HTTPS提交至伺服器並無問題。

2.密碼存儲過程中的"加密",我認為你說的是"非明文存儲"。包括加鹽-hash等,可在伺服器端完成,不必在客戶端通過JavaScript等完成

3.鑒於摘要演算法不可逆的特性,你無法做到【用戶提交時的密碼是直接hash,存儲的是加鹽後hash】

4.即便用JavaScript實現hash,你這樣的解決方案無法抵禦重放攻擊-攻擊者不需要知道明文密碼,只需要知道(加鹽後的)密碼的hash

5.不使用HTTPS,有能力篡改數據的攻擊者可以注入惡意JavaScript進而直接獲取明文的登錄憑據。

對此,電腦版新浪微博(先使用HTTPS完成"密鑰交換",即通過HTTPS安全的提供一個公鑰,再將用戶輸入的密碼用此公鑰加密,通過明文HTTP傳輸)和網易郵箱(登錄頁面未使用HTTPS,僅POST登錄憑據的URL是HTTPS)恐怕是最大的負面教材


https才是王道


HTTPS. 別折騰了。動動腦子


前台加密都是扯淡,好多答案都說要先在前台加密再傳輸到後台進行二次加密存儲,若是在Web端,根本不需要獲取密碼原文就能模擬登陸,前台加密形同虛設,那為何還需要前台加密呢?前台加密僅僅能幫助避免被網管抓包直接獲取密碼而已。若懂點HTTP請求的,壓根就是沒效果,照樣可以登陸。

我深知這一點,所以我寫的代碼,提交密碼都是明文!為何要做前端無用的加密?只怕是徒勞,增加無效代碼、勞動力罷了。


客戶端用驗證碼作為鹽值作可逆加密,傳到服務端後先解密然後再用不可逆加密與資料庫對比。詳見:
http://www.2cto.com/Article/201304/202288.html#12732-tsina-1-75385-4cfdb5a4fb74592eb67847a918275b04


不管怎麼樣,密碼是要用MD5之類的加密文後傳輸存儲


既然前提是不用https,那麼有幾種方式可以來實現:
1、用本地控制項,如ActiveX
2、用屏幕鍵盤,用戶的輸入值,每個鍵盤都是重新初始化過的,每個值輸入,只有當前用戶的Session知道,用完就刪掉,下次重新隨機生成。
3、另外類似於方案1就是常見的硬體加密,如銀行的密保


推薦閱讀:

如何使用nodejs做爬蟲程序?
Websocket為什麼在客戶端向服務端發送報文的時候需要掩碼加密,而服務端向客戶端不需要呢?
SVG 具體的應用場景是怎樣的?為什麼代替 Flash 的是 Canvas 而不是 SVG 呢?
如何評價浙江大學三名教授及一名研究生申請利用 defineProperty 做數據雙向綁定的專利?
餓了么H5站那個佔位的base64圖片是如何生成的啊?

TAG:前端開發 | JavaScript | 網路安全 | 加密 | 密碼 | 密碼加密 |