最近在做項目中的漏洞修復工作,在短時間內接觸到很多關於web開發需要防范的漏洞,例如SQL injection , XSS, CSRF等等,這些漏洞對web開發的項目來說的破壞還是比較大的,其實在網上有很多這些漏洞的介紹和防范,像SQL injection這些漏洞的注入已經很少見了。作為一個初學者我認為還是要能夠弄清楚為什么會產生這個漏洞,這樣才能從原理上理解漏洞的發生,才能更好的去修復它,本文就對XSS漏洞做一個簡單的筆記,僅供大家相互交流不斷的提升web開發的安全性。
XSS的全稱Cross-site Scripting,誇腳本攻擊,其實它的縮寫應該是CSS,但是和web開發使用的css重名了,所以就簡稱為XSS了,該漏洞在web開發中比較常見,下面演示一個XSS漏洞的過程,我自己寫了一個很簡單的web頁面(大家不要拍磚),兩個輸入框,姓名和個人介紹。
web開發中的常見漏洞,一般都發生在這些輸入框中,一般情況我們會對這些輸入域進行客戶端的校驗和服務器端的校驗,但是在客戶端的校驗基本上起不來什么作用,因為客戶端的所有代碼我們都可以進行更改,防止漏洞的發生還是需要服務器端的校驗,但是一般服務器端的校驗都是校驗你輸入的字符或者是數字的長度等等。下面就演示一個XSS的漏洞注入,當我們寫入姓名和個人介紹之后,后台代碼的處理就是進行一個簡單的轉發,然后把我們剛才的信息轉發到一個info.jsp頁面進行顯示,代碼如下(不要拍磚):
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String describe = req.getParameter("describe"); req.setAttribute("username", username); req.setAttribute("describe", describe); req.getRequestDispatcher("/info.jsp").forward(req, resp); }
我們在輸入框中這樣輸入:
大家看一下個人介紹里邊寫的是一段javascript代碼,目前我們后台沒有對javascript代碼做任何的處理,直接把輸入的信息輸出到info.jsp頁面,這個時候我們點擊提交按鈕,頁面跳轉到info.jsp頁面之后,就壞事了,直接把我們寫的javascript代碼運行了,直接彈出 hello world 提示框了。如果我們在個人介紹寫上<script>document.location.href='http://www.baidu.com'</script>,那么提交之就跳轉到百度了,如果跳轉到xxoo網站呢,這不就壞事了嘛。
如果你使用的是chrome 和 firefox瀏覽器演示例子,會發現不會出現上邊的情況,主要原因是chrome和firefox瀏覽器進行了攔截,看一下chrome瀏覽器console中的錯誤提示:
The XSS Auditor refused to execute a script in 'http://127.0.0.1:8080/javaweb/helloworld' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header. helloworld:24
如果在request的請求和response響應中包含相同的script可執行的腳本,chrome會進行攔截,難道我們使用chrome瀏覽器就可以防止XSS的出現嗎?答案肯定不是這樣的,一般情況下我們會把用戶輸入的表單內容存到數據庫中,然后再查詢的時候進行顯示,現在讓我們模擬一下查詢數據庫,顯示用戶的輸入,看看chrome會進行攔截嗎?
后台的代碼改一下,模擬查詢數據庫,是模擬:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String describe = req.getParameter("describe"); if(username == null || describe == null){ username ="aaaa"; describe="helloworld<script>alert('hello world');</script>"; } System.out.println(username +" : "+ describe); req.setAttribute("username", username); req.setAttribute("describe", describe); req.getRequestDispatcher("/info.jsp").forward(req, resp); }
在這里我們直接請求這個servlet然后再info.jsp頁面顯示信息,這個時候你會發現,我們 describe="helloworld<script>alert('hello world');</script>";這里的javascript腳本執行了,彈出的hello world 窗口。所以僅僅依靠瀏覽器防止XSS是不行的。我們需要自己在后台對這些特殊的字符進行轉碼,當這些字符再次顯示到頁面的時候不執行腳本。
使用什么樣的方法才能阻止這種情況的發生,就是對HTML 中的預留字符替換為字符實體,例如:對< 進行替換成 <,對>替換成> 等等。在這里把我們的代碼進行一下完善防止XSS的出現:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String describe = req.getParameter("describe"); if(username == null || describe == null){ username ="aaaa"; describe="helloworld<script>alert('hello world');</script>"; } //HTML 中的預留字符必須被替換為字符實體 username = StringEscapeUtils.escapeHtml4(username); describe = StringEscapeUtils.escapeHtml4(describe); System.out.println(username +" : "+ describe); req.setAttribute("username", username); req.setAttribute("describe", describe); req.getRequestDispatcher("/info.jsp").forward(req, resp); }
這個時候我們再次使用chrome瀏覽器直接訪問請求的servlet在info.jsp中顯示的結果為:
這樣我們就可以簡單的防止XSS誇腳本攻擊,代碼中的 StringEscapeUtils是apache common-lang 包下的一個工具類,這個工具類也可以對sql中的保留字符進行轉換,同時我們自己也可以自己實現一個對html中的預留字進行替換的程序。在后台打印的describe的字符已經被替換為:
helloworld<script>alert('hello world');</script> 把這些內容顯示在html中是不會執行javascript腳本的。
本人也是剛剛接觸XSS漏洞的原理,上邊舉得例子是目前最簡單的例子,一些很深入的XSS漏洞的方法還需要不斷的學習和研究,希望大家有這方面的資料可以進行一下共享。到此結束。