赞
踩
一、xss攻击
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
简单说就是说,通过在输入框输入一些js代码,如在账号密码输入框中输入
或者
这样点击提交的时候就会触发alert弹窗,分别弹出 xss 和 @@ 的内容,这里只是做个简单的演示,弹了个窗口,还能存储病毒下载地址到服务端,进入的时候自动下载,或者修改你的cookie啥的,这里感兴趣可以百度查查xss攻击。
二、如何防御
解决思路对用户提交表单的参数进行转移,如把< 转换为 < 把 > 转换为 &rt;
java有很多的过滤工具类
commons-lang
commons-lang
2.6
然后通过下面的代码即可过滤
StringEscapeUtils.escapeHtml(string);
底层也是将一切标签进行转移,达到js调用不生效的作用。
这里使用的是filter过请求进行拦截处理。
过滤的内容报过get请求的参数、对象, post形式body中的参数
1)添加xss过滤器
XssgFilter
com.train.web.filter.XssFilter
XssgFilter
/*
这里过滤了所有的请求,其中XssFilter是我们自己过滤器
2)添加自己的过滤器,
import javax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;public class XssFilter implementsFilter {
@Overridepublic void init(FilterConfig filterConfig) throwsServletException {
}
@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throwsIOException, ServletException {
XssHttpServletRequestWrapper req=newXssHttpServletRequestWrapper((HttpServletRequest)servletRequest);
filterChain.doFilter(req,servletResponse);
}
@Overridepublic voiddestroy() {
}
}
3)定义自己的http包装类
public class XssHttpServletRequestWrapper extendsHttpServletRequestWrapper {boolean isUpData = false;//判断是否是上传 上传忽略
publicXssHttpServletRequestWrapper(HttpServletRequest servletRequest) {super(servletRequest);
String contentType=servletRequest.getContentType ();if (null !=contentType)
isUpData=contentType.startsWith ("multipart");
}
@OverridepublicString[] getParameterValues(String parameter) {
String[] values= super.getParameterValues(parameter);if (values==null) {return null;
}int count =values.length;
String[] encodedValues= newString[count];for (int i = 0; i < count; i++) {
encodedValues[i]=cleanXSS(values[i]);
}returnencodedValues;
}
@OverridepublicString getParameter(String parameter) {
String value= super.getParameter(parameter);if (value == null) {return null;
}returncleanXSS(value);
}/*** 获取request的属性时,做xss过滤*/@OverridepublicObject getAttribute(String name) {
Object value= super.getAttribute(name);if (null != value && value instanceofString) {
value=cleanXSS((String) value);
}returnvalue;
}
@OverridepublicString getHeader(String name) {
String value= super.getHeader(name);if (value == null)return null;returncleanXSS(value);
}private staticString cleanXSS(String value) {
value= value.replaceAll("", ">");
value= value.replaceAll("%3C", "<").replaceAll("%3E", ">");
value= value.replaceAll("\\(", "(").replaceAll("\\)", ")");
value= value.replaceAll("%28", "(").replaceAll("%29", ")");
value= value.replaceAll("'", "'");
value= value.replaceAll("eval\\((.*)\\)", "");
value= value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value= value.replaceAll("script", "");returnvalue;
}
@Overridepublic ServletInputStream getInputStream () throwsIOException {if(isUpData){return super.getInputStream ();
}else{final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());return newServletInputStream() {
@Overridepublic int read() throwsIOException {returnbais.read();
}
@Overridepublic booleanisFinished() {return false;
}
@Overridepublic booleanisReady() {return false;
}
@Overridepublic voidsetReadListener(ReadListener readListener) { }
};
}
}publicString inputHandlers(ServletInputStream servletInputStream){
StringBuilder sb= newStringBuilder();
BufferedReader reader= null;try{
reader= new BufferedReader(new InputStreamReader (servletInputStream, Charset.forName("UTF-8")));
String line= "";while ((line = reader.readLine()) != null) {
sb.append(line);
}
}catch(IOException e) {
e.printStackTrace();
}finally{if (servletInputStream != null) {try{
servletInputStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}if (reader != null) {try{
reader.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}returncleanXSS(sb.toString ());
}
}
但是这里有个问题,假如这里还有一些特殊的需求,有些html标签是希望在前端能显示的,前端通过一些已经防止了xss攻击的富文本控件输入信息,后台不希望将这些信息转义
三、添加一些额外的内容
1)希望能动态的开关
2)期待部分接口的接口的参数是能存在标签的
添加一个xss开关的控制类, 这里使用了配置中心
importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;
@Componentpublic classXSSFilterConfigUtil {public staticBoolean openXssProtect;public staticBoolean getOpenXssProtect() {return openXssProtect == null ? false: openXssProtect;
}
@Value("${open.xss.protect}")public voidsetOpenXssProtect(Boolean openXssProtect) {
XSSFilterConfigUtil.openXssProtect=openXssProtect;
}
}
注意的是:
1. @Value无法为静态属性注入值,所以需要添加set方法为其注入值;
2. 工具类必须添加@Component或者@Service注解,否则@Value不起作用。
静态方法中注入了值以后,Filter中就可以直接使用了。
修改上面的http包装类,这里不对" 进行过滤,过滤的话,会把json的""个去除,使用@RequestBody没办法解析成为一个正常的对象
importcom.alibaba.fastjson.JSONObject;importcom.train.service.impl.XSSFilterConfigUtil;importorg.apache.commons.lang.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.nio.charset.Charset;importjava.util.HashMap;importjava.util.Map;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/*** 防护http处理
* 1.过滤xss*/
public class XssHttpServletRequestWrapper extendsHttpServletRequestWrapper {private static final Logger LOGGER = LoggerFactory.getLogger(XssHttpServletRequestWrapper.class);boolean isUpData = false;//判断是否是上传 上传忽略//不期待被过滤的的链接和字段(管理后台使用了富文本,希望有可编辑的内容)
HashMap doNotFilterURLAndParamMap = new HashMap() {
{
put("/api/v2/group/manage", "description");
put("/api/v1/sendNews", "content");
}
};/*** Constructs a request object wrapping the given request.
*
*@paramrequest The request to wrap
*@throwsIllegalArgumentException if the request is null*/
publicXssHttpServletRequestWrapper(HttpServletRequest request) {super(request);
String contentType=request.getContentType ();if (null !=contentType)
isUpData=contentType.startsWith ("multipart");
}/*** 过滤单个参数
*@paramname
*@return
*/@OverridepublicString getParameter(String name) {
String parameter= super.getParameter(name);if(StringUtils.isNotBlank(parameter) &&XSSFilterConfigUtil.getOpenXssProtect()){//这里使用的阿帕奇的common-lang3中的转义html方法,也可以自己实现,
String escapeParameter = this.cleanXSS(parameter);returnescapeParameter;
}returnparameter;
}/*** 过滤实体的每个参数
*@paramname
*@return
*/@OverridepublicString[] getParameterValues(String name) {
String[] parameterValues= super.getParameterValues(name);if (parameterValues == null) {return null;
}if(XSSFilterConfigUtil.getOpenXssProtect()) {for (int i = 0; i < parameterValues.length; ++i) {
String value=parameterValues[i];
parameterValues[i]= this.cleanXSS(value);
}
}returnparameterValues;
}/*** 处理@RequestBody的形式传入的json数据
*@return*@throwsIOException*/@Overridepublic ServletInputStream getInputStream () throwsIOException {if(!XSSFilterConfigUtil.getOpenXssProtect()) {return super.getInputStream ();
}if(isUpData){return super.getInputStream ();
}else{final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());return newServletInputStream() {
@Overridepublic int read() throwsIOException {returnbais.read();
}
};
}
}publicString inputHandlers(ServletInputStream servletInputStream){
StringBuilder sb= newStringBuilder();
BufferedReader reader= null;try{
reader= new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8")));
String line= "";while ((line = reader.readLine()) != null) {
sb.append(line);
}
}catch(IOException e) {
e.printStackTrace();
}finally{if (servletInputStream != null) {try{
servletInputStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}if (reader != null) {try{
reader.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
String requestUrl= StringUtils.replaceOnce(this.getRequestURI(), this.getContextPath(), StringUtils.EMPTY);boolean needFilter = false;
String key= "";
String param= "";for(Map.Entryentry : doNotFilterURLAndParamMap.entrySet()){
key=entry.getKey();int index = StringUtils.indexOf(key, "*");if (index > 0) {
String[] array= key.split("\\*");
StringBuffer stringBuffer= newStringBuffer();for(String s : array) {
stringBuffer.append(s).append("(.*)");
}
Pattern p=Pattern.compile(stringBuffer.toString());
Matcher m=p.matcher(requestUrl);if(m.find()) {
needFilter= true;
param=entry.getValue();break;
}
}else{if(requestUrl.equals(key)) {
needFilter= true;
param=entry.getValue();break;
}
}
}if(needFilter) { //有需要特殊处理的字段,不希望过滤标签
try{/*String param = doNotFilterURLAndParamMap.get(requestUrl);*/JSONObject jsonObject=JSONObject.parseObject(sb.toString());if(jsonObject.containsKey(param)) {
Object notFilterValue=jsonObject.get(param);
String cleanXSSParams=cleanXSS(sb.toString ());
JSONObject filteredJson=JSONObject.parseObject(cleanXSSParams);
filteredJson.put(param, notFilterValue);returnfilteredJson.toJSONString();
}else{returncleanXSS(sb.toString ());
}
}catch(Exception e) {
LOGGER.error("XssHttpServletRequestWrapper转换json数据失败",e);return cleanXSS(sb.toString ()); //异常时,就直接过滤,不管需要特殊处理的参数
}
}else{returncleanXSS(sb.toString ());
}
}/*** 过滤规则,这里不直接使用StringEscapeUtils.escapeHtml,因为获取的是一个json字符串,会将" 替换导致数据异常,没有""进行分割,无法正常注入到@RequestBody
*@paramvalue
*@return
*/
private staticString cleanXSS(String value) {
value= value.replaceAll("", ">");
value= value.replaceAll("%3C", "<").replaceAll("%3E", ">");//value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
value = value.replaceAll("%28", "(").replaceAll("%29", ")");//value = value.replaceAll("'", "'");
/*value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");*/
returnvalue;
}
}
感谢你的阅读,接外包、也找兼职
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。