Java防止xss攻擊附相關(guān)文件下載
跨站腳本(英語(yǔ):Cross-site scripting,通常簡(jiǎn)稱(chēng)為:XSS)是一種網(wǎng)站應(yīng)用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶(hù)將代碼注入到網(wǎng)頁(yè)上,其他用戶(hù)在觀看網(wǎng)頁(yè)時(shí)就會(huì)受到影響。這類(lèi)攻擊通常包含了HTML以及用戶(hù)端腳本語(yǔ)言。
XSS攻擊通常指的是通過(guò)利用網(wǎng)頁(yè)開(kāi)發(fā)時(shí)留下的漏洞,通過(guò)巧妙的方法注入惡意指令代碼到網(wǎng)頁(yè),使用戶(hù)加載并執(zhí)行攻擊者惡意制造的網(wǎng)頁(yè)程序。這些惡意網(wǎng)頁(yè)程序通常是JavaScript,但實(shí)際上也可以包括Java,VBScript,ActiveX,F(xiàn)lash或者甚至是普通的HTML。攻擊成功后,攻擊者可能得到更高的權(quán)限(如執(zhí)行一些操作)、私密網(wǎng)頁(yè)內(nèi)容、會(huì)話(huà)和cookie等各種內(nèi)容。
背景和現(xiàn)狀
當(dāng)網(wǎng)景(Netscape)最初推出JavaScript語(yǔ)言時(shí),他們也察覺(jué)到準(zhǔn)許網(wǎng)頁(yè)服務(wù)器發(fā)送可執(zhí)行的代碼給一個(gè)瀏覽器的安全風(fēng)險(xiǎn)(即使僅是在一個(gè)瀏覽器的沙盒里)。它所造成的一個(gè)關(guān)鍵的問(wèn)題在于用戶(hù)同時(shí)打開(kāi)多個(gè)瀏覽器視窗時(shí),在某些例子里,網(wǎng)頁(yè)里的片斷代碼被允許從另一個(gè)網(wǎng)頁(yè)或?qū)ο笕〕鰯?shù)據(jù),而因?yàn)閻阂獾木W(wǎng)站可以用這個(gè)方法來(lái)嘗試竊取機(jī)密信息,所以在某些情形,這應(yīng)是完全被禁止的。為了解決這個(gè)問(wèn)題,瀏覽器采用了同源決策——僅允許來(lái)自相同域名系統(tǒng)和使用相同協(xié)議的對(duì)象與網(wǎng)頁(yè)之間的任何交互。這樣一來(lái),惡意的網(wǎng)站便無(wú)法借由JavaScript在另一個(gè)瀏覽器竊取機(jī)密數(shù)據(jù)。此后,為了保護(hù)用戶(hù)免受惡意的危害,其他的瀏覽器與伺服端指令語(yǔ)言采用了類(lèi)似的訪(fǎng)問(wèn)控制決策。
XSS漏洞可以追溯到1990年代。大量的網(wǎng)站曾遭受XSS漏洞攻擊或被發(fā)現(xiàn)此類(lèi)漏洞,如Twitter[1],F(xiàn)acebook[2],MySpace,Orkut[3][4] ,新浪微博[5]和百度貼吧 。研究表明[6],最近幾年XSS已經(jīng)超過(guò)緩沖區(qū)溢出成為最流行的攻擊方式,有68%的網(wǎng)站可能遭受此類(lèi)攻擊。根據(jù)開(kāi)放網(wǎng)頁(yè)應(yīng)用安全計(jì)劃(Open Web Application Security Project)公布的2010年統(tǒng)計(jì)數(shù)據(jù),在Web安全威脅前10位中,XSS排名第2,僅次于代碼注入(Injection)。[7]
檢測(cè)方法
通常有一些方式可以測(cè)試網(wǎng)站是否有正確處理特殊字符:
<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>(這個(gè)僅于IE7(含)之前有效)
攻擊手段和目的
攻擊者使被攻擊者在瀏覽器中執(zhí)行腳本后,如果需要收集來(lái)自被攻擊者的數(shù)據(jù)(如cookie或其他敏感信息),可以自行架設(shè)一個(gè)網(wǎng)站,讓被攻擊者通過(guò)JavaScript等方式把收集好的數(shù)據(jù)作為參數(shù)提交,隨后以數(shù)據(jù)庫(kù)等形式記錄在攻擊者自己的服務(wù)器上。
常用的XSS攻擊手段和目的有:
盜用cookie,獲取敏感信息。
利用植入Flash,通過(guò)crossdomain權(quán)限設(shè)置進(jìn)一步獲取更高權(quán)限;或者利用Java等得到類(lèi)似的操作。
利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)用戶(hù)的身份執(zhí)行一些管理動(dòng)作,或執(zhí)行一些一般的如發(fā)微博、加好友、發(fā)私信等操作。
利用可被攻擊的域受到其他域信任的特點(diǎn),以受信任來(lái)源的身份請(qǐng)求一些平時(shí)不允許的操作,如進(jìn)行不當(dāng)?shù)耐镀被顒?dòng)。
在訪(fǎng)問(wèn)量極大的一些頁(yè)面上的XSS可以攻擊一些小型網(wǎng)站,實(shí)現(xiàn)DDoS攻擊的效果。
漏洞的防御和利用
過(guò)濾特殊字符
避免XSS的方法之一主要是將用戶(hù)所提供的內(nèi)容進(jìn)行過(guò)濾,許多語(yǔ)言都有提供對(duì)HTML的過(guò)濾:
PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更強(qiáng)的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect (Open Source Library)。(https://code.google.com/archive/p/xssprotect/)
Node.js的node-validator。
使用HTTP頭指定類(lèi)型
很多時(shí)候可以使用HTTP頭指定內(nèi)容的類(lèi)型,使得輸出的內(nèi)容避免被作為HTML解析。如在PHP語(yǔ)言中使用以下代碼:
<?php
header('Content-Type: text/javascript; charset=utf-8');
?>
即可強(qiáng)行指定輸出內(nèi)容為文本/JavaScript腳本(順便指定了內(nèi)容編碼),而非可以引發(fā)攻擊的HTML。
用戶(hù)方面
包括Internet Explorer、Mozilla Firefox在內(nèi)的大多數(shù)瀏覽器皆有關(guān)閉JavaScript的選項(xiàng),但關(guān)閉功能并非是最好的方法,因?yàn)樵S多網(wǎng)站都需要使用JavaScript語(yǔ)言才能正常運(yùn)作。通常來(lái)說(shuō),一個(gè)經(jīng)常有安全更新推出的瀏覽器,在使用上會(huì)比很久都沒(méi)有更新的瀏覽器更為安全。
解決提供兩個(gè)思路
1.使用過(guò)濾器過(guò)濾輸入字符,然后做相應(yīng)處理。
處理方式:
一種是保留語(yǔ)意,將輸入的特殊字符轉(zhuǎn)譯存儲(chǔ)到數(shù)據(jù)庫(kù),壞處是對(duì)數(shù)據(jù)庫(kù)或文件系統(tǒng)產(chǎn)生一些不必要的垃圾信息。
一種是過(guò)濾掉特殊字符,只保留正常數(shù)據(jù),但是有些時(shí)候用戶(hù)需要輸入特殊字符,這樣不能保證數(shù)據(jù)原始性。
一種是不讓輸入,返回異常值。
以上都可以自行進(jìn)行特殊處理,這里只提供些思路,怎么處理可以根據(jù)需求自己選擇
過(guò)濾器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>
過(guò)濾器:
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);
}
}
第一種過(guò)濾器: 使用commons-lang3-3.1.jar包的 org.apache.commons.lang3.StringEscapeUtils工具類(lèi)對(duì)特殊字符進(jìn)行轉(zhuǎn)譯。 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);
}
}
第二種過(guò)濾器:自己通過(guò)正則表達(dá)式手寫(xiě)過(guò)濾,轉(zhuǎn)譯或者消除特殊字符。
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;
}
}
第三種過(guò)濾器: 使用工具類(lèi)xssProtect,項(xiàng)目中需要引入 xssProtect-0.1.jar、antlr-3.0.1.jar、antlr-runtime-3.0.1.jar 等3個(gè) jar 包。具體實(shí)現(xiàn)沒(méi)有試驗(yàn),可以參考下這個(gè):http://liuzidong.iteye.com/blog/1744023
用maven管理jar包的話(huà),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.第二種思路就是輸入不管他,只在顯示的時(shí)候,進(jìn)行轉(zhuǎn)譯,可以用過(guò)濾器或者自行解決。
如果頁(yè)面的展示大部分都在bootstrap表單里,那么bootstrap的自帶屬性就可以解決:
escape: true,// 是否轉(zhuǎn)義 默認(rèn) 為false
個(gè)別可以自己在寫(xiě)方法轉(zhuǎn)譯,例如:
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打包下載
相關(guān)文章
Java終止線(xiàn)程實(shí)例和stop()方法源碼閱讀
這篇文章主要介紹了Java終止線(xiàn)程實(shí)例和stop()方法源碼閱讀,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12
Springboot處理配置CORS跨域請(qǐng)求時(shí)碰到的坑
本篇文章介紹了我在開(kāi)發(fā)過(guò)程中遇到的一個(gè)問(wèn)題,以及解決該問(wèn)題的過(guò)程及思路,通讀本篇對(duì)大家的學(xué)習(xí)或工作具有一定的價(jià)值,需要的朋友可以參考下2021-09-09
Spring?Security實(shí)現(xiàn)接口放通的方法詳解
在用Spring?Security項(xiàng)目開(kāi)發(fā)中,有時(shí)候需要放通某一個(gè)接口時(shí),我們需要在配置中把接口地址配置上,這樣做有時(shí)候顯得麻煩。本文將通過(guò)一個(gè)注解的方式快速實(shí)現(xiàn)接口放通,感興趣的可以了解一下2022-05-05
springCloud集成nacos config的過(guò)程
本文介紹spring cloud集成nacos config的過(guò)程,通過(guò)實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
springboot使用@KafkaListener監(jiān)聽(tīng)多個(gè)kafka配置實(shí)現(xiàn)
當(dāng)服務(wù)中需要監(jiān)聽(tīng)多個(gè)kafka時(shí),?需要配置多個(gè)kafka,本文主要介紹了springboot使用@KafkaListener監(jiān)聽(tīng)多個(gè)kafka配置實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04
java List去掉重復(fù)元素的幾種方式(小結(jié))
這篇文章主要介紹了java List去掉重復(fù)元素的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06

