理解inode
1661
2022-05-29
最近要開發一個項目,其中涉及到了用戶口令存儲(大家習慣稱之為密碼),毫不夸張的說,如果方案設計的不合格,未來再想補救就會困難重重。
記得在寫《深入淺出HTTPS:原理到實戰》這本書的時候,也研究了很多密碼學算法,和口令加密有關的算法也有很多,參考了很多資料,最近又溫習了這些資料,感覺理解的更透徹了,為了把口令加密的事情說清楚,打算寫4-5篇文章。
首先,口令加密是非常系統化的一個工程,涉及到多方面,比如代碼安全性,系統安全性,數據存儲安全性,任何一個方面出現漏洞,可能就會導致口令的泄漏。嚴格的說,誰也不能保證自己系統的用戶口令不被外泄,我們要做的就是盡可能的減少這種風險。
其次我寫的文章主要描述口令存儲方案的設計,至于 Web 程序安全,服務器安全等方面不會涉及,比如手機短信驗證、圖形驗證碼、前臺登錄限制這些策略對保護口令安全也非常重要,但不是描述的重點。
什么是口令呢?就是用戶自行設定的一段字符串,用戶要對自己的口令安全性負責,要認識到口令的重要性,因為一旦口令因為各種原因泄漏,那么攻擊者就能以用戶的身份進行任何操作。
從這個角度來看,用戶應該盡量設定強口令(比如多種字符的組合、定期修改);系統也有義務強制要求用戶使用強口令。
從破解的角度看,不管系統采用什么加密算法,強口令也更有安全性,破解的難度也會加大,從歷史上出現的口令泄漏事件來看,很多是因為用戶的口令太弱了。
從系統設計的角度看,口令存儲到磁盤(比如 Mysql)的時候,不能是明文的,道理很簡單,如果 Mysql 出現安全漏洞,比如被攻擊者拖庫了,那么攻擊者不費吹灰之力就能獲取用戶的明文口令。
通過密碼學算法可以將明文口令轉換為無規則的密文,即使攻擊者知道了口令的密文,也不能破解出口令明文,這樣相當于口令沒有泄漏(當然事情沒有那么理想,所以才需要相對完美的口令保護方案)。
那么使用什么密碼學算法呢?比較流行的解決方案就是密碼學 Hash 算法(比如 sha1),很多開發者喜歡對口令進行 Hash 運算,然后將運算值存儲到數據庫中。用戶登錄的時候,程序用同樣的 Hash 運算口令后,將運算值和數據庫中的 Hash 值進行比較,如果相同,表示登錄成功。
密碼學 Hash 算法有什么特點?大家都用它保護口令呢?根本的原因在于密碼學 Hash 算法具備單向性,也就是說 Hash 值不能被反解,同時不同的口令其 Hash 值是不一樣的,嚴格的說密碼學 Hash 算法很難發生碰撞。
為什么我一直強調密碼學 Hash算法,普通的 Hash 算法能運算口令嗎?不能,普通的 Hash 算法主要用于數據結構中(比如 Hash 表),它很容易發生 Hash 碰撞,想想看,不同的口令如果 Hash 值一樣,那么我用自己的口令也許能登錄別人的賬戶了。
所以說只有安全的密碼學 Hash 算法才能用于保護口令,另外也要注意的是 Hash 運算口令不代表加密,因為它不是加密算法(對稱加密算法,非對稱加密算法才是)。
那么對于口令來說,應該使用 md5 還是 sha1 算法?本質上并沒有太大的差別,雖然這二種算法理論上已經發生了碰撞,但在實際使用過程中很難找到兩個不同值具備相同的 Hash 值。尤其對 Hash 進行加鹽后(后面會說),選用 md5 還是 sha1 沒有太大的差別。
如果單純用密碼學 Hash 算法運算口令,很容易被破解,接下去說說幾種攻擊方法。
(1)字典攻擊和暴力攻擊
比如攻擊者拖庫了,得到了所有的口令 Hash 值,現在的目的就是找出口令明文。字典攻擊和暴力攻擊并沒有太大的區別,字典攻擊可以認為是暴力攻擊的一種,它將常用的字符(暴力攻擊是將各種可能的字符)組合起來進行 Hash 運算,然后和數據庫中的 Hash 值進行比較,如果相同,表示用戶的口令被成功破解。
密碼學 Hash 算法如果用于運算口令,有個最致命的弱點就是它的運算速度太快了,如果僅僅對口令進行 Hash 運算,那么很容易被破解;而且如果口令本身就是弱口令,那么破解的速度就更快了。
不管采取何種解決方案,都有可能被暴力破解,只是時間的問題。但如果采用相對完善的 Hash 解決方案(比如 Hash 加鹽,后面會講),那么被暴力破解的幾率會小很多。
有些同學們會問,如果沒有被拖庫,暴力攻擊還能進行嗎?也可以,攻擊者可以組合各種字符,然后調用登錄接口,不斷進行攻擊,如果接口返回成功,表示口令被破解了。
為了避免這樣的攻擊,可以采取驗證碼和其它策略保護登錄接口,但這是另外一個層面的問題了。
(2)查找表
這是比字典攻擊更有效的一種方式,攻擊同種 Hash 算法非常有效率。基本的做法就是預運算字典中的口令,然后將口令和口令對應的密文存儲到一個數據結構中(比如 Hash 表或者 Memcached),然后可根據口令明文和密文進行查找,查找速度非常快。
(3)彩虹表
彩虹表和查找表很類似,查找表使用的存儲較多,運算速度較快;而彩虹表存儲較小,運算較慢,相當于用空間換時間。
原理我并沒有研究,最重要的就是 R 運算(reduce function),它不是 Hash 函數的反函數,它能將一個 Hash 值轉換為一個明文(不是明文)。
構建彩虹表的過程:對一個口令組合進行不斷的 Hash 運算、R 運算,持續 k 次后得到一條鏈,然后將鏈條的頭部和尾部存儲起來(中間的不要)。
那么如何破解呢?同學們還是直接看 wiki 或找一些專門的文章,在此文中,只要記住,彩虹表能夠破解口令明文,而且很有效。
那么如何防止彩虹表和查找表攻擊呢?最好的方法就是 Hash 加鹽(Hash+salt)。或者這么說,如果將來你要設計口令存儲方案,Hash 加鹽雖然不是最好的方法,但如果實施得當,也是比較安全的。
簡單 Hash 就是對口令進行單純 Hash 運算,Hash 加鹽是在口令后面加一段隨機值(salt),然后再進行 Hash 運算。
不管是彩虹表還是查找表,如果兩個用戶的口令相同,他們的密文也必定相同,攻擊就相對容易,構建的口令組合相對減少,一個用戶的口令密文被破解后,那么具有相同口令密文的用戶其口令也被破解了。
而加鹽就是保證同樣的口令其密文值不一樣,這樣攻擊者構建的彩虹表和查找表的將非常巨大,破解的速度和成功率將極低,換句話說,優秀的口令存儲方案就在于即使被拖庫了,攻擊者也沒有啥辦法。
現在重點就是 salt 值如何設置了,salt 一定要不可預測,且高度隨機,如果可預測的話,攻擊者就能猜測出 salt,這樣即使 Hash 加鹽了,本質上和純 Hash 加密沒有區別。
那么如何生成 salt 呢?請使用密碼學中的偽隨機函數(CSPRNG),比如 PHP 語言中可以使用 openssl_random_pseudo_bytes() 函數,千萬不要使用非安全的 rand() 函數。安全的偽隨機函數的關鍵在于種子(seed),此處就不多描述了,記住一點,獲取 salt 需用標準的密碼學算法,不要想當然自行設計。
salt 值獲取還有幾個誤區,比如使用和用戶有關的屬性(比如 email,手機號)充當用戶的 salt,這樣很容易被猜測。
也要避免使用全局 salt,如果將全局 salt 值硬編碼,那么一旦代碼泄漏或服務器被攻擊,攻擊者在構建字典的時候,在各種字符組合后面加上 slat,然后再 hash,想想看,是不是很容易攻擊?
全局 salt 另外一個弱點在于,攻擊者很容易找出規律,因為相同口令其密文值也是相同的。
salt 值也不能太短,理論上 salt 長度應該和 Hash 值長度一致。
一個設計良好的 salt,攻擊基本很難成功,想象下,一個口令再加上 salt,攻擊者要構建多少個 Hash 算法的輸入值?而且有了 salt,即使用戶的口令相對弱一點,也能有效保障用戶的安全性。
Hash 加鹽的根本目標是:即使被拖庫了,攻擊者也很難破解出密文。雖然它不是標準的口令安全存儲解決方案,但從結果上來看,也是非常不錯的一種設計。
最后非常非常重要的一點就是,salt 不能和口令密文存儲在一起,不然就和沒有 salt 一樣,因為攻擊者拖庫后,構建字典非常簡單,因為它能夠直接看到 salt,所以一定要分開存儲(比如在不同的機器上),這樣即使口令密文表被拖庫了,而 salt 表沒有被拖庫,也是相對安全的。
salt 看上去雖然是毫無規則的,但本質上是明文的,所以如果想進一步安全,可以可以引入一個 pepper(一個公共密鑰),那么如何加密保護 salt 或密文口令呢?有兩種辦法。
(1)在計算密文口令的時候,采用 HMAC 方法(內部還是一個 Hash 算法):
口令密文=hash(口令+salt+pepper)
(2)或者對密文口令進行加密(對稱加密算法或非對稱加密算法)
口令密文=rsa(hash(口令+salt),pepper)
不管采用那種方案,pepper 的安全性非常重要,因為這個 pepper 一旦泄露,對于保護口令沒有太大的作用。
但不管怎么說,使用 pepper 還是很有積極意義的,畢竟增加了一層保護。
解決方案永遠沒有絕對安全的,只有相對的,至于 pepper 采用那種處理方法,后一篇博文我會描述。
這篇博文是原理性的,下一篇我將實際描述一個解決方案,敬請期待~
歡迎大家關注我的公眾號(ID:yudadanwx,虞大膽的嘰嘰喳喳),所有文章都是原創,主要來源于平時工作中遇到的問題和學習中的一些想法;也可以了解我的書《深入淺出HTTPS:從原理的實戰》
本文轉載自異步社區。
原文鏈接:https://www.epubit.com/articleDetails?id=N4457e03a-2b1a-4b36-9b49-5d402db7fe24
通用安全 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。