一、xss攻击

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

简单说就是说,通过在输入框输入一些js代码,如在账号密码输入框中输入

<video src=1 onerror=alert(/xss/)/>

或者

 <script>alert("@@") </script>

这样点击提交的时候就会触发alert弹窗,分别弹出 xss  和 @@ 的内容,这里只是做个简单的演示,弹了个窗口,还能存储病毒下载地址到服务端,进入的时候自动下载,或者修改你的cookie啥的,这里感兴趣可以百度查查xss攻击。

二、如何防御

解决思路对用户提交表单的参数进行转移,如把< 转换为 &lt;  把 > 转换为 &rt;

java有很多的过滤工具类

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

然后通过下面的代码即可过滤

StringEscapeUtils.escapeHtml(string); 

底层也是将一切标签进行转移,达到js调用不生效的作用。

这里使用的是filter过请求进行拦截处理。

过滤的内容报过get请求的参数、对象, post形式body中的参数

1)添加xss过滤器

        <!-- xss过滤器 -->
<filter>
<filter-name>XssgFilter</filter-name>
<filter-class>com.train.web.filter.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XssgFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

这里过滤了所有的请求,其中XssFilter是我们自己过滤器

2)添加自己的过滤器,

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
XssHttpServletRequestWrapper req=new XssHttpServletRequestWrapper((HttpServletRequest)servletRequest); filterChain.doFilter(req,servletResponse);
} @Override
public void destroy() { }
}

3)定义自己的http包装类

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
boolean isUpData = false;//判断是否是上传 上传忽略
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
String contentType = servletRequest.getContentType ();
if (null != contentType)
isUpData =contentType.startsWith ("multipart");
} @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] = cleanXSS(values[i]);
}
return encodedValues;
} @Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
} /**
* 获取request的属性时,做xss过滤
*/
@Override
public Object getAttribute(String name) {
Object value = super.getAttribute(name);
if (null != value && value instanceof String) {
value = cleanXSS((String) value);
}
return value;
} @Override
public String getHeader(String name) { String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private static String cleanXSS(String value) {
value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
value = value.replaceAll("%3C", "&lt;").replaceAll("%3E", "&gt;");
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", "");
return value;
} @Override
public ServletInputStream getInputStream () throws IOException {
if (isUpData){
return super.getInputStream ();
}else{ final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); return new ServletInputStream() { @Override
public int read() throws IOException {
return bais.read();
} @Override
public boolean isFinished() {
return false;
} @Override
public boolean isReady() {
return false;
} @Override
public void setReadListener(ReadListener readListener) { }
};
} }
public String inputHandlers(ServletInputStream servletInputStream){
StringBuilder sb = new StringBuilder();
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();
}
}
}
return cleanXSS(sb.toString ());
}
}

但是这里有个问题,假如这里还有一些特殊的需求,有些html标签是希望在前端能显示的,前端通过一些已经防止了xss攻击的富文本控件输入信息,后台不希望将这些信息转义

三、添加一些额外的内容

1)希望能动态的开关

2)期待部分接口的接口的参数是能存在标签的

添加一个xss开关的控制类, 这里使用了配置中心

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Component
public class XSSFilterConfigUtil { public static Boolean openXssProtect; public static Boolean getOpenXssProtect() {
return openXssProtect == null ? false : openXssProtect;
} @Value("${open.xss.protect}")
public void setOpenXssProtect(Boolean openXssProtect) {
XSSFilterConfigUtil.openXssProtect = openXssProtect;
} }

注意的是:

  1. @Value无法为静态属性注入值,所以需要添加set方法为其注入值;

  2. 工具类必须添加@Component或者@Service注解,否则@Value不起作用。

静态方法中注入了值以后,Filter中就可以直接使用了。

修改上面的http包装类,这里不对" 进行过滤,过滤的话,会把json的""个去除,使用@RequestBody没办法解析成为一个正常的对象

import com.alibaba.fastjson.JSONObject;
import com.train.service.impl.XSSFilterConfigUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* 防护http处理
* 1.过滤xss
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { private static final Logger LOGGER = LoggerFactory.getLogger(XssHttpServletRequestWrapper.class); boolean isUpData = false;//判断是否是上传 上传忽略 //不期待被过滤的的链接和字段(管理后台使用了富文本,希望有可编辑的内容)
HashMap<String, String> doNotFilterURLAndParamMap = new HashMap<String, String>() {
{
put("/api/v2/group/manage", "description");
put("/api/v1/sendNews", "content"); }
}; /**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
String contentType = request.getContentType ();
if (null != contentType)
isUpData =contentType.startsWith ("multipart");
} /**
* 过滤单个参数
* @param name
* @return
*/
@Override
public String getParameter(String name) {
String parameter = super.getParameter(name);
if(StringUtils.isNotBlank(parameter) && XSSFilterConfigUtil.getOpenXssProtect()){
//这里使用的阿帕奇的common-lang3中的转义html方法,也可以自己实现,
String escapeParameter = this.cleanXSS(parameter);
return escapeParameter;
}
return parameter;
} /**
* 过滤实体的每个参数
* @param name
* @return
*/
@Override
public String[] 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);
}
} return parameterValues; } /**
* 处理@RequestBody的形式传入的json数据
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream () throws IOException {
if(!XSSFilterConfigUtil.getOpenXssProtect()) {
return super.getInputStream ();
} if (isUpData){
return super.getInputStream ();
}else{ final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); return new ServletInputStream() { @Override
public int read() throws IOException {
return bais.read();
}
};
} } public String inputHandlers(ServletInputStream servletInputStream){
StringBuilder sb = new StringBuilder();
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.Entry<String, String> entry : doNotFilterURLAndParamMap.entrySet()){ key = entry.getKey(); int index = StringUtils.indexOf(key, "*");
if (index > 0) {
String[] array = key.split("\\*");
StringBuffer stringBuffer = new StringBuffer();
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);
return filteredJson.toJSONString();
}else {
return cleanXSS(sb.toString ());
} }catch (Exception e) {
LOGGER.error("XssHttpServletRequestWrapper转换json数据失败",e);
return cleanXSS(sb.toString ()); //异常时,就直接过滤,不管需要特殊处理的参数
} }else {
return cleanXSS(sb.toString ());
}
} /**
* 过滤规则,这里不直接使用StringEscapeUtils.escapeHtml,因为获取的是一个json字符串,会将" 替换导致数据异常,没有""进行分割,无法正常注入到@RequestBody
* @param value
* @return
*/
private static String cleanXSS(String value) {
value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
value = value.replaceAll("%3C", "&lt;").replaceAll("%3E", "&gt;");
// 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", "");*/
return value;
} }

java 拦截器解决xss攻击的更多相关文章

  1. 记一次JAVA WEB项目解决XSS攻击的办法(亲测有效)

    什么是XSS攻击 简单来说,XSS 攻击是页面被注入了恶意的代码,度娘一大堆的东西,不想说 系统架构主要是SSM框架,服务层另外使用了DubboX.   为啥说这个,因为SpringMVC对于Xss攻 ...

  2. Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 >>>>>>>>>>>>>>&g ...

  3. spring boot集成swagger,自定义注解,拦截器,xss过滤,异步调用,guava限流,定时任务案例, 发邮件

    本文介绍spring boot集成swagger,自定义注解,拦截器,xss过滤,异步调用,定时任务案例 集成swagger--对于做前后端分离的项目,后端只需要提供接口访问,swagger提供了接口 ...

  4. Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求   Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 java ...

  5. java 拦截器

    一.前言 这是一篇关于 java 拦截器的文章,是我的写 java  web 所遇见的问题.当我们写好一个网站,必须要通过登陆页面才可以进入这个系统.那么我们就得写个 java 拦截器,如果是通过登录 ...

  6. 拦截过滤防御XSS攻击 -- Struts2.3 以及 2.5 的解决方式

    使用Struts2框架开发的后台在防御XSS攻击的时候很多方式都不能用,因为Struts2对请求进行的二次封装有区别.以下针对Struts2的XSS攻击进行拦截过滤防御解决: Struts2.3 本方 ...

  7. Spring mvc拦截器防御CSRF攻击

    CSRF(具体参考百度百科) CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSR ...

  8. Java Web学习(十)Java拦截器

    文章更新时间:2020/04/07 一.引言 既然要用拦截器,首先先得简单了解一下什么是拦截器: 概念:java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Actio ...

  9. java 拦截器和过滤器区别(转载)

    1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的 ...

随机推荐

  1. 【Mac】anaconda自定义channels

    1.查看channels conda config --show channels 输出 channels: - defaults 2.添加channels conda config --add ch ...

  2. DBUtils 使用方法

    导包  jar  DBUtils.jar QueryRunner中提供对sql语句操作的API. update(Connection conn, String sql, Object... param ...

  3. 这次终于可以愉快的进行 appium 自动化测试了

    appium 是进行 app 自动化测试非常成熟的一套框架.但是因为 appium 设计到的安装内容比较多,很多同学入门都跪在了环境安装的部分.本篇讲述 appium 安卓环境的搭建,希望让更多童鞋轻 ...

  4. 一、CentOS6.8安装MySQL5.6

    一.官网下载rpm安装包 https://dev.mysql.com/downloads/ 版本选中如图中红色框 二.卸载旧mysql 1.检查是否安装有mysql rpm -qa | grep -i ...

  5. Java IO(七)ByteArrayInputStream 和 ByteArrayOutputStream

    Java IO(七)ByteArrayInputStream 和 ByteArrayOutputStream 一.介绍 ByteArrayInputStream 和 ByteArrayOutputSt ...

  6. 一篇文章看清楚 Linux 的职业发展方向

    手机.汽车.甚至宇宙飞船,在今天的科技世界中,你几乎到处都能看到 Linux 的身影.前两天 SpaceX 成功将宇航员送入太空的猎鹰9号火箭与龙飞船用的也是 Linux的操作系统.身处与 Linux ...

  7. MyBatis特性详解

    缓存简介 一般我们在系统中使用缓存技术是为了提升数据查询的效率.当我们从数据库中查询到一批数据后将其放入到混存中(简单理解就是一块内存区域),下次再查询相同数据的时候就直接从缓存中获取数据就行了. 这 ...

  8. ActiveMQ 笔记(七)ActiveMQ的多节点集群

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.Activemq 的集群思想 1.使用Activemq集群的原因 面试题: 引入消息中间件后如何保证 ...

  9. 面试题: SpringBoot 的自启动原理

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 引言 不论在工作中,亦或是求职面试,Spring Boot 已经成为我们必知必会的技能项.除了比较老旧的 ...

  10. Vue中将网址、动态网址转为二维码

    1. 首先需要安装相关的依赖包 npm install qrcodejs2 --save 或者 npm install qrcode2 --save 这里选择第二种方式进行安装,如图: 2.templ ...