Java防止xss攻擊附相關檔案下載
跨站指令碼(英語:Cross-site scripting,通常簡稱為:XSS)是一種網站應用程式的安全漏洞攻擊,是程式碼注入的一種。它允許惡意使用者將程式碼注入到網頁上,其他使用者在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及使用者端指令碼語言。
XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令程式碼到網頁,使使用者載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是JavaScript,但實際上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到更高的許可權(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。
背景和現狀
當網景(Netscape)最初推出JavaScript語言時,他們也察覺到准許網頁伺服器傳送可執行的程式碼給一個瀏覽器的安全風險(即使僅是在一個瀏覽器的沙盒裡)。它所造成的一個關鍵的問題在於使用者同時開啟多個瀏覽器視窗時,在某些例子裡,網頁裡的片斷程式碼被允許從另一個網頁或物件取出資料,而因為惡意的網站可以用這個方法來嘗試竊取機密資訊,所以在某些情形,這應是完全被禁止的。為了解決這個問題,瀏覽器採用了同源決策——僅允許來自相同域名系統和使用相同協議的物件與網頁之間的任何互動。這樣一來,惡意的網站便無法藉由JavaScript在另一個瀏覽器竊取機密資料。此後,為了保護使用者免受惡意的危害,其他的瀏覽器與伺服端指令語言採用了類似的訪問控制決策。
XSS漏洞可以追溯到1990年代。大量的網站曾遭受XSS漏洞攻擊或被發現此類漏洞,如Twitter[1],Facebook[2],MySpace,Orkut[3][4],新浪微博[5]和百度貼吧。研究表明[6],最近幾年XSS已經超過緩衝區溢位成為最流行的攻擊方式,有68%的網站可能遭受此類攻擊。根據開放網頁應用安全計劃(Open Web Application Security Project)公佈的2010年統計資料,在Web安全威脅前10位中,XSS排名第2,僅次於程式碼注入(Injection)。[7]
檢測方法
通常有一些方式可以測試網站是否有正確處理特殊字元:
<script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert (vulnerable)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" onerror="alert('XSS')">
<div style="height:expression(alert('XSS'),1)"></div>(這個僅於IE7(含)之前有效)
攻擊手段和目的
攻擊者使被攻擊者在瀏覽器中執行指令碼後,如果需要收集來自被攻擊者的資料(如cookie或其他敏感資訊),可以自行架設一個網站,讓被攻擊者通過JavaScript等方式把收集好的資料作為引數提交,隨後以資料庫等形式記錄在攻擊者自己的伺服器上。
常用的XSS攻擊手段和目的有:
盜用cookie,獲取敏感資訊。
利用植入Flash,通過crossdomain許可權設定進一步獲取更高許可權;或者利用Java等得到類似的操作。
利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)使用者的身份執行一些管理動作,或執行一些一般的如發微博、加好友、發私信等操作。
利用可被攻擊的域受到其他域信任的特點,以受信任來源的身份請求一些平時不允許的操作,如進行不當的投票活動。
在訪問量極大的一些頁面上的XSS可以攻擊一些小型網站,實現DDoS攻擊的效果。
漏洞的防禦和利用
過濾特殊字元
避免XSS的方法之一主要是將使用者所提供的內容進行過濾,許多語言都有提供對HTML的過濾:
PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更強的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect (Open Source Library)。(https://code.google.com/archive/p/xssprotect/)
Node.js的node-validator。
使用HTTP頭指定型別
很多時候可以使用HTTP頭指定內容的型別,使得輸出的內容避免被作為HTML解析。如在PHP語言中使用以下程式碼:
<?php
header('Content-Type: text/javascript; charset=utf-8');
?>
即可強行指定輸出內容為文字/JavaScript指令碼(順便指定了內容編碼),而非可以引發攻擊的HTML。
使用者方面
包括Internet Explorer、Mozilla Firefox在內的大多數瀏覽器皆有關閉JavaScript的選項,但關閉功能並非是最好的方法,因為許多網站都需要使用JavaScript語言才能正常運作。通常來說,一個經常有安全更新推出的瀏覽器,在使用上會比很久都沒有更新的瀏覽器更為安全。
解決提供兩個思路
1.使用過濾器過濾輸入字元,然後做相應處理。
處理方式:
一種是保留語意,將輸入的特殊字元轉譯儲存到資料庫,壞處是對資料庫或檔案系統產生一些不必要的垃圾資訊。
一種是過濾掉特殊字元,只保留正常資料,但是有些時候使用者需要輸入特殊字元,這樣不能保證資料原始性。
一種是不讓輸入,返回異常值。
以上都可以自行進行特殊處理,這裡只提供些思路,怎麼處理可以根據需求自己選擇
過濾器web.xml:
<filter> <filter-name>XSSFilter</filter-name> <filter-class>com.***.web.filter.XSSFilter</filter-class> </filter> <filter-mapping> <filter-name>XSSFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
過濾器:
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class XSSFilter implements Filter { FilterConfig filterConfig = null; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } @Override public void destroy() { this.filterConfig = null; } @Override public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException { chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request),response); } }
第一種過濾器: 使用commons-lang3-3.1.jar包的 org.apache.commons.lang3.StringEscapeUtils工具類對特殊字元進行轉譯。 Example:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.lang3.StringEscapeUtils; public class XSSRequestWrapper extends HttpServletRequestWrapper { public XSSRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); } @Override public String getHeader(String name) { return StringEscapeUtils.escapeHtml4(super.getHeader(name)); } @Override public String getQueryString() { return StringEscapeUtils.escapeHtml4(super.getQueryString()); } @Override public String getParameter(String name) { return StringEscapeUtils.escapeHtml4(super.getParameter(name)); } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values != null) { int length = values.length; String[] escapseValues = new String[length]; for (int i = 0; i < length; i++) { escapseValues[i] = StringEscapeUtils.escapeHtml4(values[i]); } return escapseValues; } return super.getParameterValues(name); } }
第二種過濾器:自己通過正則表示式手寫過濾,轉譯或者消除特殊字元。
Example:
import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class XSSRequestWrapper extends HttpServletRequestWrapper { public XSSRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); } @Override public String[] getParameterValues(String parameter) { String[] values = super.getParameterValues(parameter); if (values == null) { return null; } int count = values.length; String[] encodedValues = new String[count]; for (int i = 0; i < count; i++) { encodedValues[i] = stripXSS(values[i]); } return encodedValues; } @Override public String getParameter(String parameter) { String value = super.getParameter(parameter); return stripXSS(value); } @Override public String getHeader(String name) { String value = super.getHeader(name); return stripXSS(value); } private String stripXSS(String value) { if (value != null) { // Avoid null characters value = value.replaceAll("",""); // Avoid anything between script tags Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid anything in a src='...' type of expression scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome </script> tag scriptPattern = Pattern.compile("</script>",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome <script ...> tag scriptPattern = Pattern.compile("<script(.*?)>",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid eval(...) expressions scriptPattern = Pattern.compile("eval\\((.*?)\\)",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid expression(...) expressions scriptPattern = Pattern.compile("expression\\((.*?)\\)",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid javascript:... expressions scriptPattern = Pattern.compile("javascript:",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid vbscript:... expressions scriptPattern = Pattern.compile("vbscript:",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid οnlοad= expressions scriptPattern = Pattern.compile("onload(.*?)=",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); } return value; } }
第三種過濾器: 使用工具類xssProtect,專案中需要引入 xssProtect-0.1.jar、antlr-3.0.1.jar、antlr-runtime-3.0.1.jar 等3個 jar 包。具體實現沒有試驗,可以參考下這個:http://liuzidong.iteye.com/blog/1744023
用maven管理jar包的話,pom.xml如下:
<!-- https://mvnrepository.com/artifact/org.antlr/antlr --> <dependency> <groupId>org.antlr</groupId> <artifactId>antlr</artifactId> <version>3.0.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.antlr/antlr-runtime --> <dependency> <groupId>org.antlr</groupId> <artifactId>antlr-runtime</artifactId> <version>3.0.1</version> </dependency>
2.第二種思路就是輸入不管他,只在顯示的時候,進行轉譯,可以用過濾器或者自行解決。
如果頁面的展示大部分都在bootstrap表單裡,那麼bootstrap的自帶屬性就可以解決:
escape: true,// 是否轉義 預設 為false
個別可以自己在寫方法轉譯,例如:
var escapeHTML = function (text) { if (typeof text === 'string') { return text .replace(/&/g,'&') .replace(/</g,'<') .replace(/>/g,'>') .replace(/"/g,'"') .replace(/'/g,''') .replace(/`/g,'`'); } return text; };
附件:
xssProtect-0.1.jar、antlr-3.0.1.jar、antlr-runtime-3.0.1.jar打包下載