b < c 引發的安全性思考
軟體工程中,不論使用哪種開發語言,安全性一直是一個非常棘手卻又重要的問題。安全性是軟體開發領域永遠的主題之一,而且隨著網際網路的蜂擁發展而帶動的新技術的興起與革命(比如近幾年火起來的node.js,python,go等,甚至微軟也開源後的.net Core),軟體工程中的安全性更加的凸顯與重要了。
那麼,什麼才是危險的呢?我的第一反應是注入攻擊,比如SQL注入攻擊。一個典型的場景是WEB應用中,使用者登陸功能,根據使用者輸入的使用者名稱密碼獲取相應的資料,那麼SQL注入就應運而生,模擬使用者名稱,密碼加入特殊字元,加入惡意指令碼等等手段,進而造成不了可挽回的後果。比如,正常腳本當如:
select * from userInfo where username='input_Name' and password='input_Pwd or'
那麼,如果是這樣的呢?
select * from userInfo where username='input_Name' and password='input_Pwdte' or 1=1 or ''
關於如何編寫安全的Java程式碼,Sun官方給了一份指南,有興趣的同學可以參考這篇文章,大致為:
• 靜態欄位 • 縮小作用域 • 公共方法和欄位 • 保護包 • equals方法 • 如果可能使物件不可改變 • 不要返回指向包含敏感資料的內部陣列的引用 • 不要直接儲存使用者提供的陣列 • 序列化 • 原生函式 • 清除敏感資訊
比如,DoS是一種常見的網路攻擊,有人戲稱為“洪水攻擊”。其慣用手法是通過某種手段,比如大量的機器傳送請求,將目標網站寬頻和其資源耗盡,導致使用者無法正常訪問,甚至伺服器的宕機。
而對於此類問題,如果單從伺服器級別考慮,多少欠缺,我們或許需要考慮程式級別的攻擊,比如Java,JVM,以及涉及到的執行緒方面的安全,應用程式的瑕疵等進行低成本的DoS攻擊。
而在面試中,我們都會被問到安全性的問題,卻大多比較多泛泛,大而廣,而大多數的安全性問題都與程式碼安全性有關。我們回顧下Java程式碼的執行過程:
首先編譯器把.java檔案程式設計成.class位元組碼檔案,然後由類載入器負責把.class檔案載入到JVM,再由位元組碼校驗進行校驗,然後由Java直譯器負責把該類檔案解釋為機器碼執行。
在類載入器載入.class檔案到java虛擬機器的過程中,類載入器通過區分本機檔案系統的類和網路系統匯入的類增加安全性(不允許網路上的應用程式修改本地的資料),本機的類先被載入,一旦所有的類載入完,執行檔案的記憶體劃分就固定了,然後位元組碼校驗器開始校驗.class位元組碼檔案,位元組碼校驗器不檢查那些可信任的編譯器所產生的類檔案。通過之後,java直譯器材負責把類檔案解釋成為機器碼進行執行。
// a b c 都是int型別的數值 if (a - b < c) { // … }
這段看似簡單,沒毛病的程式碼會引發下列問題:
如果b<0,而造成的資料溢位,你能想象出多少問題?!而對於越界的處理雖然Java底層給出了很好的解決,但是數值而造成記憶體問題不容小覷。
當然,過多的考慮安全性問題,勢必會造成應用程式的冗餘甚至疲軟,這些需要視情況而定,而不可蓋棺而論。
再比如,對於一段可能出現問題的程式碼,常用手段 try … catch(){… },那麼問題來了,catch的是什麼?而一般情況下,我們程式需要抓取到catch,因為要做日誌處理,那麼日誌中不可或缺的有類似程式碼位置,方法名,以及錯誤原因等,甚至包含了敏感資訊。當然,不可避免,我的建議是,儘量使用內部標識的異常資訊,而返回給客戶端的類似異常訊息儘量少的自動返回的異常訊息。
對於安全標準特別高的系統,甚至可能要求敏感資訊被使用後,要立即明確再記憶體中銷燬,以免被探測到;或者避免在發生core dump時,意外暴露。
開發和測試階段
1. 儘量的規範化程式碼,可參考《阿里巴巴開發手冊》
2. 儘量多的code review,避免不必要尷尬程式碼出現
3. 在程式碼check-in等環節,利用hook機制去呼叫規則檢查工具,保證不合規範程式碼進入OpenJDK程式碼庫
部署階段
可參考JDK在加密方法的路線圖
以上皆為日常開發總結,也借鑑網上大神的文章,略略整理一二,權作學習使用,當然面試能幫到不慎感動了,以後有機會再做梳理。
歡迎指點。