1. 程式人生 > >31、你瞭解Java應用開發中的注入攻擊嗎?

31、你瞭解Java應用開發中的注入攻擊嗎?

安全是軟體開發領域永遠的主題之一,隨著新技術浪潮的興起,安全的重要性愈發凸顯出來,對於金融等行業,甚至可以說安全是企業的生命線。不論是移動裝置、普通 PC、小型機,還是大規模分散式系統,以及各種主流作業系統,Java 作為軟體開發的基礎平臺之一,可以說是無處不在,自然也就成為安全攻擊的首要目標之一。

今天我要問你的問題是,你瞭解 Java 應用開發中的注入攻擊嗎?

典型回答

注入式(Inject)攻擊是一類非常常見的攻擊方式,其基本特徵是程式允許攻擊者將不可信的動態內容注入到程式中,並將其執行,這就可能完全改變最初預計的執行過程,產生惡意效果。

下面是幾種主要的注入式攻擊途徑,原則上提供動態執行能力的語言特性,都需要提防發生注入攻擊的可能。

首先,就是最常見的 SQL 注入攻擊。一個典型的場景就是 Web 系統的使用者登入功能,根據使用者輸入的使用者名稱和密碼,我們需要去後端資料庫核實資訊。

假設應用邏輯是,後端程式利用介面輸入動態生成類似下面的 SQL,然後讓 JDBC 執行。

Select * from use_info where username = “input_usr_name” and password = “input_pwd”

但是,如果我輸入的 input_pwd 是類似下面的文字,

 “ or “”=”

那麼,拼接出的 SQL 字串就變成了下面的條件,OR 的存在導致輸入什麼名字都是複合條件的。

Select * from use_info where username = “input_usr_name” and password = “” or “” = “”

這裡只是舉個簡單的例子,它是利用了期望輸入和可能輸入之間的偏差。上面例子中,期望使用者輸入一個數值,但實際輸入的則是 SQL 語句片段。類似場景可以利用注入的不同 SQL 語句,進行各種不同目的的攻擊,甚至還可以加上“;delete xxx”之類語句,如果資料庫許可權控制不合理,攻擊效果就可能是災難性的。

第二,作業系統命令注入。Java 語言提供了類似 Runtime.exec(…) 的 API,可以用來執行特定命令,假設我們構建了一個應用,以輸入文字作為引數,執行下面的命令:

ls –la input_file_name

但是如果使用者輸入是 “input_file_name;rm –rf /*”,這就有可能出現問題了。當然,這只是個舉例,Java 標準類庫本身進行了非常多的改進,所以類似這種程式設計錯誤,未必可以真的完成攻擊,但其反映的一類場景是真實存在的。

第三,XML 注入攻擊。Java 核心類庫提供了全面的 XML 處理、轉換等各種 API,而 XML 自身是可以包含動態內容的,例如 XPATH,如果使用不當,可能導致訪問惡意內容。

還有類似 LDAP 等允許動態內容的協議,都是可能利用特定命令,構造注入式攻擊的,包括 XSS(Cross-site Scripting)攻擊,雖然並不和 Java 直接相關,但也可能在 JSP 等動態頁面中發生。

 

考點分析

今天的問題是安全領域的入門題目,我簡單介紹了最常見的幾種注入場景作為示例。安全本身是個非常大的主題,在面試中,面試官可能會考察安全問題,但如果不是特定安全專家崗位,瞭解基礎的安全實踐就可以滿足要求了。

Java 工程師未必都要成為安全專家,但瞭解基礎的安全領域常識,有利於發現和規避日常開發中的風險。今天我會側重和 Java 開發相關的安全內容,希望可以起到一個拋磚引玉的作用,讓你對 Java 開發安全領域有個整體印象。

  •   談到 Java 應用安全,主要涉及哪些安全機制?
  •   到底什麼是安全漏洞?對於前面提到的 SQL 注入等典型攻擊,我們在開發中怎麼避免?

 

知識擴充套件

首先,一起來看看哪些 Java API 和工具構成了 Java 安全基礎。很多方面我在專欄前面的講解中已經有所涉及,可以簡單歸為三個主要組成部分:

第一,執行時安全機制。可以簡單認為,就是限制 Java 執行時的行為,不要做越權或者不靠譜的事情,具體來看:

  •   在類載入過程中,進行位元組碼驗證,以防止不合規的程式碼影響 JVM 執行或者載入其他惡意程式碼。
  •   類載入器本身也可以對程式碼之間進行隔離,例如,應用無法獲取啟動類載入器(Bootstrap Class-Loader)物件例項,不同的類載入器也可以起到容器的作用,隔離模組之間不必要的可見性等。目前,Java Applet、RMI 等特性已經或逐漸退出歷史舞臺,類載入等機制總體上反倒在不斷簡化。
  •   利用 SecurityManger 機制和相關的元件,限制程式碼的執行時行為能力,其中,你可以定製 policy 檔案和各種粒度的許可權定義,限制程式碼的作用域和許可權,例如對檔案系統的操作許可權,或者監聽某個網路埠的許可權等。我畫了一個簡單的示意圖,對執行時安全的不同層次進行了整理。


可以看到,Java 的安全模型是以程式碼為中心的,貫穿了從類載入,如 URLClassLoader 載入網路上的 Java 類等,到應用程式執行時許可權檢查等全過程。

  •   另外,從原則上來說,Java 的 GC 等資源回收管理機制,都可以看作是執行時安全的一部分,如果相應機制失效,就會導致 JVM 出現 OOM 等錯誤,可看作是另類的拒絕服務。

 

第二,Java 提供的安全框架 API,這是構建安全通訊等應用的基礎。例如:

  •   加密、解密 API。
  •   授權、鑑權 API。
  •   安全通訊相關的類庫,比如基本 HTTPS 通訊協議相關標準實現,如TLS 1.3;或者附屬的類似證書撤銷狀態判斷(OSCP)等協議實現。

注意,這一部分 API 內部實現是和廠商相關的,不同 JDK 廠商往往會定製自己的加密演算法實現。

 

第三, 就是 JDK 整合的各種安全工具,例如:

  •   keytool,這是個強大的工具,可以管理安全場景中不可或缺的祕鑰、證書等,並且可以管理 Java 程式使用的 keystore 檔案。
  •   jarsigner,用於對 jar 檔案進行簽名或者驗證。


在應用實踐中,如果對安全要求非常高,建議開啟 SecurityManager,

-Djava.security.manager

請注意其開銷,通常只要開啟 SecurityManager,就會導致 10% ~ 15% 的效能下降,在 JDK 9 以後,這個開銷有所改善。

理解了基礎 Java 安全機制,接下來我們來一起探討安全漏洞(Vulnerability)。

按照傳統的定義,任何可以用來繞過系統安全策略限制的程式瑕疵,都可以算作安全漏洞。具體原因可能非常多,設計或實現中的疏漏、配置錯誤等,任何不慎都有可能導致安全漏洞出現,例如惡意程式碼繞過了也Java 沙箱的限制,獲取了特權等。如果你想了解更多安全漏洞的資訊,可以從通用安全漏洞庫(CVE)等途徑獲取,瞭解安全漏洞評價標準。

但是,要達到攻擊的目的,未必都需要繞過許可權限制。比如利用雜湊碰撞發起拒絕服務攻擊(DOS,Denial-Of-Service attack),常見的場景是,攻擊者可以事先構造大量相同雜湊值的資料,然後以 JSON 資料的形式傳送給伺服器端,伺服器端在將其構建成為 Java 物件過程中,通常以 Hastable 或 HashMap 等形式儲存,雜湊碰撞將導致雜湊表發生嚴重退化,演算法複雜度可能上升一個數量級(HashMap 後續進行了改進,我在專欄第 9 講介紹了樹化機制),進而耗費大量 CPU 資源。

 

像這種攻擊方式,無關於許可權,可以看作是程式實現的瑕疵,給了攻擊者以低成本進行進攻的機會。

我在開頭提到的各種注入式攻擊,可以有不同角度、不同層面的解決方法,例如針對 SQL 注入:

  •   在資料輸入階段,填補期望輸入和可能輸入之間的鴻溝。可以進行輸入校驗,限定什麼型別的輸入是合法的,例如,不允許輸入標點符號等特殊字元,或者特定結構的輸入。
  •   在 Java 應用進行資料庫訪問時,如果不用完全動態的 SQL,而是利用 PreparedStatement,可以有效防範 SQL 注入。不管是 SQL 注入,還是 OS 命令注入,程式利用字串拼接生成執行邏輯都是個可能的風險點!
  •   在資料庫層面,如果對查詢、修改等許可權進行了合理限制,就可以在一定程度上避免被注入刪除等高破壞性的程式碼。


在安全領域,有一句準則:安全傾向於 “明顯沒有漏洞”,而不是“沒有明顯漏洞”。所以,為了更加安全可靠的服務,我們最好是採取整體性的安全設計和綜合性的防範手段,而不是頭痛醫頭、腳痛醫腳的修修補補,更不能心存僥倖。

一個比較普適的建議是,儘量使用較新版本的 JDK,並使用推薦的安全機制和標準。如果你有看過 JDK release notes,例如8u141,你會發現 JDK 更新會修復已知的安全漏洞,並且會對安全機制等進行增強。但現實情況是,相當一部分應用還在使用很古老的不安全版本 JDK 進行開發,並且很多資訊處理的也很隨意,或者通過明文傳輸、儲存,這些都存在暴露安全隱患的可能。

今天我首先介紹了典型的注入攻擊,然後整理了 Java 內部的安全機制,並探討了到底什麼是安全漏洞和典型的表現形式,以及如何防範 SQL 注入攻擊等,希望對你有所幫助。

 

一課一練

關於今天我們討論的題目你做到心中有數了嗎?今天的思考題是,你知道 Man-In-The-Middle(MITM)攻擊嗎?有哪些常見的表現形式?如何防範呢?