由于公司的产品准备全面互联网化,所以就对安全问题进行了一系列的排查,排查过程中发现了xss脚本攻击的问题,开始着手了解和修改代码
xss攻击的简单解释
跨站脚本(Cross-site scripting,通常简称为XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
—维基百科跨站脚本
通过开源项目Antisamy防御Xss攻击
Antisamy是owasp下的开源项目(下载地址,需要翻墙),主要用于防御富文本的xss攻击。
需要说明的是,在实际情况中,最经常出现的攻击情况是输入框的js代码传入和按钮的url篡改,但是由于实际业务的需要,我们并不能严格控制输入框的内容为汉字或者数字,所以应当对输入进行过滤。
引入Antisamy包
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.5.5</version>
</dependency>```
这段代码是通过maven工具引入antisamy最新版本的jar包到项目中,如果没有使用maven项目,就需要手动下载jar包在项目中建立依赖。
jar包中的xml文件
antisamy jar包中包含多个xml配置文件,用于配置项目中允许输入的内容。其中有
antisamy-ebay.xml文件是ebay网站使用的过滤富文本输入的配置文件,其他几个带有公司名称后缀的配置文件是相应公司使用的配置策略。需要注意的是antisamy-anythinggoes.xml文件,这个文件允许所有有效的html和css元素输入,但是拒绝javascript和css相关的网络钓鱼攻击。一般不推荐使用,但是可以当作参考,用于研究策略文件定义的基本规则。
Antisamy项目使用
项目的使用并不复杂,下面给出一个最简单的思路
//定义过滤的策略
Policy policy = Policy.getInstance("file"); //此处的file指使用的策略文件,如antisamy-ebay.xml
//对html输入进行过滤
Antisamy antisamy = new Antisamy();
CleanResult cr = antisamy.scan(innerHtml,policy);
//输出过滤后安全的html或异常信息
String cleanHtml = cr.getCleanHTML();
String errMsg = cr.getErrorMessages();
而在项目中的使用是这样的:
- 定义一个filter
package com.vivi.test.xssfilter;
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 {
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
System.out.println("enter xssFilter----------------------------");
chain.doFilter(new XssRequestWrapper((HttpServletRequest) request),
response);
}
public void destroy() {
// TODO Auto-generated method stub
}
}
- 重写request
package com.vivi.test.xssfilter;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.log4j.Logger;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;
public class XssRequestWrapper extends HttpServletRequestWrapper {
private static Policy policy = null;
public static Logger logger = Logger.getLogger(XssRequestWrapper.class);
static {
try {
policy = Policy.getInstance(XssRequestWrapper.class
.getClassLoader().getResourceAsStream("antisamy-ebay.xml"));
} catch (PolicyException e) {
e.printStackTrace();
}
}
public XssRequestWrapper(HttpServletRequest request) {
super(request);
}
@SuppressWarnings("rawtypes")
public Map<String, String[]> getParameterMap() {
Map<String, String[]> request_map = super.getParameterMap();
Iterator iterator = request_map.entrySet().iterator();
System.out.println("request_map" + request_map.size());
logger.debug("request_map" + request_map.size());
while (iterator.hasNext()) {
Map.Entry me = (Map.Entry) iterator.next();
System.out.println(me.getKey() + ":");
String[] values = (String[]) me.getValue();
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
logger.debug(values[i]);
values[i] = xssClean(values[i]);
}
}
return request_map;
}
public String[] getParameterValues(String paramString) {
String[] arrayOfString1 = super.getParameterValues(paramString);
if (arrayOfString1 == null)
return null;
int i = arrayOfString1.length;
String[] arrayOfString2 = new String[i];
for (int j = 0; j < i; j++)
arrayOfString2[j] = xssClean(arrayOfString1[j]);
return arrayOfString2;
}
public String getParameter(String paramString) {
String str = super.getParameter(paramString);
if (str == null)
return null;
return xssClean(str);
}
public String getHeader(String paramString) {
String str = super.getHeader(paramString);
if (str == null)
return null;
return xssClean(str);
}
private String xssClean(String value) {
AntiSamy antiSamy = new AntiSamy();
try {
if (policy.equals(null)) {
getPolicy();
}
final CleanResults cr = antiSamy.scan(value, policy);
// 安全的HTML输出
return cr.getCleanHTML();
} catch (ScanException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
return value;
}
private void getPolicy() throws PolicyException {
try {
policy = Policy.getInstance(XssRequestWrapper.class
.getClassLoader().getResourceAsStream("antisamy-ebay.xml"));
} catch (PolicyException e) {
e.printStackTrace();
}
}
}
实际使用起来也特别方便。
时间所限,这是上篇,下篇写antisamy原理的简单解析。