在我從業的這么多年時間里,我為各種小型初創企業、大型銀行以及電信運營商進行過無數次的代碼安全審計,而且在閑暇時間我也閱讀過stackoverflow.com上數百篇的安全文章。至此,我總結出了目前開發人員最容易犯的十大加密錯誤。本系列分上下集,希望大家能夠從中得到一些加密方面的啟示。
不幸的是,錯誤使用加密方法的情況比比皆是,而且錯誤使用的情況遠遠要比正確使用的情況出現得更加頻繁。不過,很多問題是由于加密API本身的復雜性(開發文檔描述不清)和不安全性(默認配置不安全)所導致的,也并非錯誤都處在開發人員的身上。Java可以算得上是目前存在問題最為嚴重的開發語言之一,而也許Java應該從它的“敵人” .Net身上學到一些東西,例如如何開發出更加方便使用的加密API,或者降低安全問題出現的可能性等等。
導致目前情況不容樂觀的另外一個原因也許是很多安全問題往往需要我們對代碼進行人工分析才可以發現,而只有經過專業培訓的安全專家才能夠完成這項任務。根據我的從業經驗來看,很多熱門的靜態分析工具在尋找加密方面的問題時效率和成功率都不高,而且黑盒滲透測試幾乎無法發現這種問題。
因此,我希望這篇文章中的內容可以幫助那些代碼審計人員以及開發者們提高對軟件加密方面的認知。
文章結構如下:
1. 硬編碼密鑰
2. 初始化向量選擇不當
3. ECB操作模式
4. MD5死而不僵,SHA1仍茍存于世
5. 誤用加密原語(用于密碼存儲)
6. 密碼未加密
7. 通過加密保證信息完整性
8. 非對稱密鑰長度不足
9. 不安全的隨機性
10. 加密雞湯
接下來,讓我給大家細細道來。
一、 硬編碼密鑰
這種情況非常的常見,硬編碼密鑰往往意味著能夠訪問軟件的人手中都有可以解密數據的密鑰(對于那些想說“代碼混淆”的開發人員,我已經為你準備好了第十條)。理想情況下,我們并不希望加密密鑰能夠對人類可見,但這畢竟是理想狀態。因此,我們只能退而求其次地去限制密鑰的訪問,并且只允許安全團隊訪問這個密鑰,而開發人員不允許訪問產品密鑰,尤其是那些本不應該出現在源代碼庫中的密鑰。

硬編碼密鑰也表現出了開發人員對密鑰管理方面的問題思考不足。密鑰管理是一個非常復雜的話題,并且超出了本文所要討論的范圍。但我想表達的是,如果密鑰被攻擊了,那么我們只有發布新版本的軟件才能替換掉原先已被攻擊的硬編碼密鑰,而在發布新版本之前往往需要大量的時間和成本來進行測試,但是在密鑰已被破解的情況下這種成本是必須要承擔的。
安全專家可以輕松地告訴開發人員那些是不應該做的,但事實卻總是不盡如人意,因為出于某種原因,我們想讓他們做到的往往在實踐過程中是不可行的。因此,開發人員通常需要采取一些折中措施。
因此我認為,使用一個配置文件可能會是更好的選擇,雖然這并不是完美的解決方案,但這至少要比使用硬編碼密鑰要好得多。雖然某些框架提供了加密配置選項,但開發人員真正需要的是一個用于測試環境和開發環境的測試密鑰,而安全技術團隊可以在真正將產品投放市場時用真正的密鑰來替換掉測試密鑰。
上面的這個建議是我在一個真實的案例中所總結出來的。當時,有一個研發團隊在產品中錯誤地存放了一個RSA公鑰,而這個密鑰是無法進行解密的,因為他們手中并沒有并沒有相對應的私鑰。而我認為,軟件需要一種測試方法來確保其中的密鑰可以正常加密/解密,或者至少開發過程中需要有一個環節來確保程序能夠按照預期運行。
二、 初始化向量(IV)選擇不當
IV指的是初始化向量。這種情況往往出現在CBC加密模式的使用過程中,而且通常存在于硬編碼IV中。有時開發人員會使用密鑰或SALT值,但最終的結果仍是每一次使用的都是相同的IV。我所見過的最糟糕的情況,就是將密鑰當作IV來使用。我在Crypto101的7.6章討論了這種行為的危險性,感興趣的同學可以自行點擊查閱。【傳送門】

當你在使用CBC加密模式時,你需要使用隨機的或不可預測的IV。在Java中,使用SecureRandom;在.Net中,使用GenerateIV。而且你這一次選擇出的IV只能使用一次,你不可以在其他加密過程中再一次使用這個IV。對于每一次加密,你都要生成一個新的IV。如果你沒有選擇出何時的IV,那么加密的安全性就得不到保障了,一個最好的例子就是SSL/TLS的實現,其中牽扯到大量選擇不當的IV。
如果你想了解更多關于初始化向量(IV)和隨機數的操作模式,請參考這篇文章。【傳送門】
三、 ECB模式
當你在使用AES這樣的分組密碼進行加密時,你應該選擇一種滿足你需要的操作模式。而你最不應該選擇的就是ECB(電碼本)模式。
無論你使用的是哪一種分組密碼,但如果你使用了ECB模式,那就是非常不安全的,因為它會泄漏明文信息,尤其是當重復的明文變成重復的密文時。如果你認為這不重要,那么請你看一看下面這張圖片:

你可以看到,采用ECB模式加密后的結果保密性非常差,而采用類似CBC和CTR這樣的安全加密模式則安全性會有大幅提升。需要注意的是,像Java這樣的編程語言所提供的API默認使用的是ECB模式。
簡而言之,不要使用ECB模式。如果你想了解更多有關安全加密模式的內容,請參考這篇文章。【傳送門】四、 MD5死而不僵,SHA1仍茍存于世
實際上,MD5早在10年前就已經被破解了,而安全人員更加在20年前就已經開始警告不要再去使用MD5了。但是我發現,現在有很多人仍在使用它。
而理論上SHA1也早已被破解,但外界真正見到的首次攻擊是近期才被曝光的。這一點Google就做得非常好,他們在研究人員正式宣布SHA1被破解之前就已經放棄在證書中使用SHA1了,但由于歷史遺留問題,很多開發源碼中仍然有SHA1的存在。

每當我在開發者的代碼中看到加密哈希函數的身影時,我都會非常擔心,因為這些人通常都不知道自己將要面對的是什么。在密碼學領域中,消息認證代碼、數字簽名算法、以及各種偽隨機數生成器使用的通常都是哈希函數,但如果讓開發人員直接使用哈希函數的話,就像是把一支機關槍交到了一名八歲小孩的手上一樣,鬼知道會發生什么。各位開發者們,你們確定這些函數真的是你需要的嗎?
總結
接下來,我們會在本系列文章的下集中跟大家詳細討論剩下的六大開發者可能會遇到的加密問題,感興趣的同學可以關注黑吧安全網的最新動態。
|