SQL注入
注入攻擊漏洞,例如SQL,OS以及LDAP注入。這些攻擊發(fā)生在當不可信的數(shù)據(jù)作為命令或者查詢語句的一部分,被發(fā)送給解釋器的時候。攻擊者發(fā)送的惡意數(shù)據(jù)可以欺騙解釋器,以執(zhí)行計劃外的命令或者在未被恰當授權(quán)時訪問數(shù)據(jù)。

SQL注入.png
我是否存在注入漏洞?
- 檢測應(yīng)用程序是否存在注入漏洞的最好辦法就是確認所有解釋器的使用都明確地將不可信數(shù)據(jù)從命令語句或查詢語句中區(qū)分出來。如果可能的話,在許多情況下,建議避免解釋器,或禁用它(如,XXE)。對于SQL調(diào)用,這就意味著在所有準備語句(prepared statements)和存儲過程(stored procedures)中使用綁定變量(bind variables),并避免使用動態(tài)查詢語句。
- 檢查應(yīng)用程序是否安全使用解釋器的最快最有效的方法是代碼審查。代碼分析工具能幫助安全分析者找到使用解釋器的代碼并追蹤應(yīng)用的數(shù)據(jù)流。滲透測試者通過創(chuàng)建攻擊的方法來確認這些漏洞。
可以執(zhí)行應(yīng)用程序的自動動態(tài)掃描器能夠提供一些信息,幫助確認一些可利用的注入漏洞是否存在。然而,掃描器并非總能達到解釋器,所以不容易檢測到一個攻擊是否成功。不恰當?shù)腻e誤處理使得注入漏洞更容易被發(fā)現(xiàn)。
攻擊案例場景
- 場景#1:應(yīng)用程序在下面存在漏洞的SQL語句的構(gòu)造中使用不可信數(shù)據(jù):
String query = "SELECT * FROM accounts WHEREcustID='" + request.getParameter("id") +"'"; - 場景#2:同樣的,框架應(yīng)用的盲目信任,仍然可能導(dǎo)致查詢語句的漏洞。(例如:Hibernate查詢語言(HQL)):
Query HQLQuery= session.createQuery(“FROM accounts
WHERE custID='“ + request.getParameter("id") + "'");
在這兩個案例中,攻擊者在瀏覽器中將“id”參數(shù)的值修改成’ or’1’=’1。如:
http://example.com/app/accountView?id=' or '1'='1
這樣查詢語句的意義就變成了從accounts表中返回所有的記錄。更危險的攻擊可能導(dǎo)致數(shù)據(jù)被篡改甚至是存儲過程被調(diào)用。
如何防止注入漏洞?
防止注入漏洞需要將不可信數(shù)據(jù)從命令及查詢中區(qū)分開。
- 參數(shù)化語句:使用占位符或綁定常量來向SQL查詢提供參數(shù),可避免或解決很多在應(yīng)用中經(jīng)常見到的SQL注入問題,還有擁有相比現(xiàn)代數(shù)據(jù)庫效率更高的優(yōu)勢(數(shù)據(jù)可以根據(jù)提供的預(yù)處理語句來優(yōu)化查詢,從而提高后續(xù)查詢的性能)。
- 輸入驗證:測試應(yīng)用接受的輸入以保證其符合應(yīng)用中定義標準的過程??梢院唵蔚綄?shù)限制成某種類型,也可以復(fù)雜到使用正則表達式或業(yè)務(wù)邏輯來驗證輸入
- 白名單驗證(包含驗證或者正驗證): 數(shù)據(jù)類型、 數(shù)據(jù)大小、 數(shù)據(jù)范圍、 數(shù)據(jù)內(nèi)容
- 黑名單:常用方法為正則表達式(推薦使用白名單)
- 編碼輸出:對在應(yīng)用的不同模塊或部分間傳遞的內(nèi)容進行編碼(根據(jù)不同的數(shù)據(jù)編碼進行替換后傳輸)
- 規(guī)范化:將輸入簡化成便準簡單的形式(通常最容易實現(xiàn)的一種方法是拒絕所有不符合規(guī)范格式的輸入)
- 通過設(shè)計來避免SQL注入的危險:
- 使用存儲過程:可以防止或減輕SQL注入影響的設(shè)計技術(shù)(幾乎可以杜絕SQL注入);
存儲過程非常有助于減輕潛在SQL注入漏洞的嚴重影響,因為大多數(shù)數(shù)據(jù)庫中使用存儲過程時可以在數(shù)據(jù)庫層配置訪問控制;發(fā)現(xiàn)SQL注入時,可以通過正確的配置來保證攻擊者無法訪問數(shù)據(jù)的敏感信息。- 使用抽象層:常見做法是為表示、業(yè)務(wù)邏輯、和數(shù)據(jù)訪問定義不同的層,從而將每一層的實現(xiàn)從總體設(shè)計中抽象出來。
處理敏感數(shù)據(jù):考慮數(shù)據(jù)庫中敏感信息的存儲和訪問
- 口令:存儲每個用戶的口令的salted單向哈希而不是口令本身,將salt(一種附加的少量隨機數(shù)數(shù)據(jù))與哈希口令分開保存;登錄時不用比較用戶口令和數(shù)據(jù)庫保存的口令,而是通過用戶提供的信息計算出salted哈希與數(shù)據(jù)庫中保存的哈希值進行比較(如果用戶忘記了口令,則生成一個新的口令給用戶)。
- 信用卡及其他財務(wù)信息:使用認可的(FIPS認證過)加密算法來對信用卡等信息進行加密,存儲加密后的明細數(shù)據(jù)。
- 存檔:考慮每隔一段合理的時間就存檔或清除這些不需要的信息。
- 避免明顯的對象名:為關(guān)鍵對象(加密函數(shù)、口令、信用卡列)選取名稱是需要格外小心,eg:password
- 創(chuàng)建數(shù)據(jù)庫honeypot:有人在嘗試從數(shù)據(jù)庫中讀取口令時接收警告,則可以創(chuàng)建一種帶password(包含假數(shù)據(jù))的附加honeypot(蜜罐),如果假數(shù)據(jù)被選中,那么發(fā)送郵件給應(yīng)用管理員。
- 附加安全的開發(fā)資源:借助資源向開發(fā)人員提供工具、資源、培訓和知識,提高安全性。
- 平臺層防御:
- 使用運行時保護(成本):檢測、減輕或防止那些不需要重編譯易受攻擊的應(yīng)用的源碼,即可部署的SQL注入。
- Web應(yīng)用防火墻:(WAF:網(wǎng)絡(luò)設(shè)備或?qū)踩约拥絎eb應(yīng)用中的一種解決方案)
- 截斷過濾器:在請求資源的核心處理之前或之后執(zhí)行處理操作。
- 不可編輯的輸入保護和可編輯的輸入保護
- URL策略/頁面層策略
頁面覆寫:創(chuàng)建一個在運行時接受的替代頁面或類
URL重寫:接收那些發(fā)送給易受攻擊頁面或URL請求,并將他們重定向該頁面的替代版本- 資源代理/封裝
- 面向方面編程
- 應(yīng)用入侵檢測系統(tǒng)
- 數(shù)據(jù)庫防火墻
- 確保數(shù)據(jù)庫安全
- 使用較低權(quán)限的數(shù)據(jù)庫登錄
- 撤銷PUBLIC許可
- 使用存儲過程
- 使用強大的加密技術(shù)來保護存儲的敏感數(shù)據(jù)
- 維護一個審查跟蹤
- 確保數(shù)據(jù)庫安全
- 額外的系統(tǒng)對象鎖定
- 約束即席查詢
- 增強對驗證周邊的控制
- 在最低權(quán)限的操作系統(tǒng)賬戶語境中運行
- 確保數(shù)據(jù)庫服務(wù)器打了補丁
- 額外的部署考慮
- 最小化不必要信息泄露
- 隱藏錯誤信息
- 使用空的默認Web站點
- 為DNS反向查詢使用虛擬主機名稱
- 使用通配符SSL證書
- 限制通過搜索引擎hacking得到的發(fā)現(xiàn)
- 禁止WSDL信息
- 提高Web服務(wù)器日志的冗余
- 在獨立主機上部署Web服務(wù)器和數(shù)據(jù)庫服務(wù)器
- 配置網(wǎng)絡(luò)訪問控制
防止LDAP注入
Function LDAPRequest(id)
LDAPRequest = checkLDAP(Request(id))
end function
'防止LDAP的注入
Function checkLDAP(strHTML)
If Isnull(strHTML) Then
checkLDAP = ""
Exit Function
End If
strHTML=server.HTMLEncode(strHTML)
Dim objRegExp,strOutput
Set objRegExp=New Regexp
objRegExp.IgnoreCase=true
objRegExp.Global=True
objRegExp.Pattern = Chr(0)
strOutput = objRegExp.Replace(strHTML, "")
objRegExp.Pattern = """"
strOutput = objRegExp.Replace(strOutput, """)
objRegExp.Pattern = "\\"
strOutput = objRegExp.Replace(strOutput, "\5c")
objRegExp.Pattern = "NUL"
strOutput = objRegExp.Replace(strOutput, "\0")
objRegExp.Pattern = "/"
strOutput = objRegExp.Replace(strOutput, "\2f")
objRegExp.Pattern = "\*"
strOutput = objRegExp.Replace(strOutput, "\2a")
objRegExp.Pattern = "\("
strOutput = objRegExp.Replace(strOutput, "\28")
objRegExp.Pattern = "\)"
strOutput = objRegExp.Replace(strOutput, "\29")
Set objRegExp=Nothing
checkLDAP = strOutput
end function