對於 Web 應用程式,安全登入是很重要的。但是目前大多數 Web 系統在發送登入密碼時是發送的明文,這樣很容易被入侵者監聽到密碼。當然,通過 SSL 來實現安全連線是個不錯的方法,但是很多情況下我們沒辦法將伺服器設定為帶有 SSL 的 Web 服務器。因此如果在登入系統中加入安全登入機制,則可以在沒有 SSL 的 Web 服務器上實現安全登入。
要實現安全登入,可以採用下面兩種方法,一種基於非對稱式加密演算法,另一種基於 hmac 演算法。下面我們來分別討論這兩種方法。
非對稱式加密演算法中,目前最常用的是 RSA 演算法和 ECC(橢圓曲線密碼編譯)演算法。要採用非對稱式加密演算法實現安全登入的話,首先需要在用戶端向伺服器端請求登入頁面時,伺服器產生公開金鑰和私密金鑰,然後將公開金鑰隨登入頁面一起傳遞給用戶端瀏覽器,當使用者輸入完使用者名稱密碼點擊登入時,登入頁面中的 JavaScript 調用非對稱式加密演算法對使用者名稱和密碼用用公開金鑰進行加密。然後在提交到伺服器端,然後伺服器端利用私密金鑰進行解密,然後跟資料庫中的使用者名稱密碼進行比較,如果一致,則登入成功,否則登入失敗。
看上去很簡單,但是這裡有這樣幾個問題。目前 RSA 演算法中,1024-2048 位的密鑰被認為是安全的。如果密鑰長度小於這個長度,則認為可以被破解。但這樣的長度超過了程式設計語言本身所允許的數字運算範圍,需要通過類比來實現大數運算。而在 Web 系統的用戶端,如果通過 JavaScript 來類比大數啟動並執行話,效率將會是很低的,因此要在用戶端採用這樣的密鑰來加密資料的話,許多瀏覽器會發出執行時間過長,停止啟動並執行警告。然而,解密或者密鑰產生的時間相對於加密來說要更長。雖然解密和密鑰產生是在伺服器端執行的,但是如果伺服器端是 PHP、ASP 這樣的指令碼語言的話,它們也將很難勝任這樣的工作。ECC 演算法的密鑰長度要求比 RSA 演算法要低一些,ECC 演算法中 160 位的密鑰長度被認為與 RSA 演算法中 1024 位的密鑰長度的安全性是等價的。雖然仍然要涉及的類比大數運算,但 ECC 演算法的密鑰長度的運算量還算是可以接受的,但是 ECC 演算法比 RSA 演算法要複雜的多,因此實現起來也很困難。
對稱式加密演算法比非對稱式加密演算法要快得多,為什麼不採用對稱式加密演算法呢?因為對稱式加密演算法需要資料發送方和接受方共用一個密鑰,因此如果要在 Web 系統的發送方也就是用戶端瀏覽器對密碼進行加密的話,就需要先從伺服器端擷取密鑰,但密鑰的傳遞可能會被監聽,加密以後的資料如果也被同時監聽到的話,入侵者就可以直接利用監聽到的密鑰來對加密後的資訊進行解密了。
但是如果我們不採用密碼編譯演算法而採用散列演算法對登入密碼進行處理的話,可以避免被直接解密出原文,但是如果直接採用 MD5 或者 SHA1 來對登入密碼進行處理後提交的話,一旦入侵者監聽到散列後的密碼,則不需要解密出原文,直接將監聽到的資料提交給伺服器,就可以實現入侵的目的了。而且,目前 MD5 演算法已被破解,SHA1 演算法則被證明從理論上可破解,就算採用離線碰撞,也可以找出與原密碼等價的密碼來。所以直接採用 MD5 或者 SHA1 來對密碼進行散列處理也是不可行的。
但是如果在散列演算法中加入了密鑰,情況就不一樣了。hmac 演算法正好作了這樣的事情,下面我們來看看如何用 hmac 演算法實現安全登入。首先在用戶端向伺服器端請求登入頁面時,伺服器端產生一個隨機字串,連同登入頁面一同發送給用戶端瀏覽器,當使用者輸入完使用者名稱密碼後,將密碼採用 MD5 或者 SHA1 來產生散列值作為密鑰,伺服器端發送來的隨機字串作為訊息資料,進行 hmac 運算。然後將結果提交給伺服器。之所以要對使用者輸入的密碼進行散列後再作為密鑰,而不是直接作為密鑰,是為了保證密鑰足夠長,而又不會太長。伺服器端接受到用戶端提交的資料後,將儲存在伺服器端的隨機字串和使用者密碼進行相同的運算,然後進行比較,如果結果一致,則認為登入成功,否則登入失敗。
這裡用戶端每次請求時伺服器端發送的隨機字串都是不同的,因此即使入侵者監聽到了這個隨機字串和加密後的提交的資料,它也無法再次提交相同的資料通過驗證。而且通過監聽到的資料也無法計算出密鑰,所以也就無法偽造登入資訊了。
因此目前來看,用 hmac 演算法來實現安全登入系統的方法是最可行的。