SpringBoot过滤XSS脚本攻击
XSS攻击是什么
XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
简而言之,就是作恶用户通过表单提交一些前端代码,如果不做处理的话,这些前端代码将会在展示的时候被浏览器执行。
如何避免XSS攻击
这里我根据个人经验做一个总结,可能经验也有不足之处。我个人解决XSS攻击是通过后端转译的办法来解决的。在实际项目中,react、vue等前后端完全分离的框架似乎已经帮我们处理了XSS脚本,这个本人对于前端略懂皮毛而已,这里就不做探讨了。下面主要实现以后端做XSS过滤。
代码实现
对于过滤XSS脚本的代码,通过搜索引擎可以搜索到很多,但似乎都不是那么全面。基本上都是只能过滤querystring类型的入参,而不能过滤json类型的入参。其实,在现在的开发中,更多的是使用json类型做数据交互。下面就直接贴代码了:
XssAndSqlHttpServletRequestWrapper.java
package com.loger.filter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* @author wbs
* 防止XSS攻击
*/
public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (!StringUtils.isEmpty(value)) {
value = StringEscapeUtils.escapeHtml4(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
if (parameterValues == null) {
return null;
}
for (int i = 0; i < parameterValues.length; i++) {
String value = parameterValues[i];
//这个过滤xss攻击的工具类,现在是借助第三方插件使用的。 也可以自己写一个工具类 比如下面的 XssUtil
parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
//自定义工具类
//parameterValues[i] = XssUtil.xssEncode(parameterValues[i]);
} return parameterValues; } }
简单讲解下,这里重写了两个方法:getParameter和getParameterValues,getParameter方法是直接通过request获得querystring类型的入参调用的方法。如果是通过springMVC注解类型来获得参数的话,走的是getParameterValues的方法。
StringEscapeUtils.escapeHtml4这个方法来自Apache的工具类,maven坐标如下:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.4</version>
</dependency>
//如果使用的是上面黄色的自定义工具类,来过滤xss 关键字,就需要导入下面XssUtils工具类,如果不使用的话下面这个工具类,就直接跳过不需要管。 但是有些人说为啥有第三方工具类,还要使用自定义工具类呢,
应为使用第三方插件时,进行代码扫描时(我们公司项目上线需要进行代码扫描)会有问题(这个问题不影响代码使用),所以我用的是自定义类。总之这两种 工具类都可以用,不影响功能的实现。
/**
* @Author wbs
* @Description Web防火墙工具类
*/
public class XssUtil { public static final String REPLACE_STRING = "*"; private XssUtil() {
} /**
* xss校验
* @param s
* @return
*/
public static String xssEncode(String s) {
if (StringUtils.isEmpty(s)) {
return s;
} else {
s = stripXSSAndSql(s);
}
StringBuilder sb = new StringBuilder(s.length() + 16);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '>':
sb.append(">");// 转义大于号
break;
case '<':
sb.append("<");// 转义小于号
break;
case '\'':
sb.append("'");// 转义单引号
break;
case '\"':
sb.append(""");// 转义双引号
break;
case '&':
sb.append("&");// 转义&
break;
case '#':
sb.append("#");// 转义#
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
} /**
* xss校验
* @param value
* @return
*/
public static String stripXSSAndSql(String value) {
if (StringUtils.isNotEmpty(value)) {
// Avoid null characters
value = value.replaceAll(" ", REPLACE_STRING);
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid anything in a src="http://www.yihaomen.com/article/java/..." type of e-xpression
scriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid e-xpression(...) expressions
scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid onload= expressions
scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(REPLACE_STRING);
// Avoid /r /n:... expressions
scriptPattern = Pattern.compile("\"\\\\s*|\\t|\\r|\\n\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
} }
过滤的代码写完了,下面就是在一个filter中应用该代码。
XssFilter.java
package com.loger.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author wbs
*/
@WebFilter(filterName = "xssFilter", urlPatterns = "/*", asyncSupported = true)
@Component public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req); chain.doFilter(xssRequestWrapper, response); } @Override public void destroy() { } /** * 过滤json类型的 * @param builder * @return */ @Bean @Primary public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) { //解析器 ObjectMapper objectMapper = builder.createXmlMapper(false).build(); //注册xss解析器 SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer"); xssModule.addSerializer(new XssStringJsonSerializer()); objectMapper.registerModule(xssModule); //返回 return objectMapper; } }
就这样,过滤querystring类型的代码已经完成(xssObjectMapper这个是后面过滤json类型才用到的)。下面来实现过滤json类型的代码:
XssStringJsonSerializer.java
package com.loger.filter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.text.StringEscapeUtils;
import java.io.IOException;
public class XssStringJsonSerializer extends JsonSerializer<String> {
@Override
public Class<String> handledType() {
return String.class;
}
@Override
public void serialize(String value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
if (value != null) {
String encodedValue = StringEscapeUtils.escapeHtml4(value);
jsonGenerator.writeString(encodedValue);
}
}
}
这里通过修改SpringMVC的json序列化来达到过滤xss的目的的。其实也可以通过第一种方法,重写getInputStream方法来实现,但由于得到的是ServletInputStream,不太好处理。(通过json类型传参会走getInputStream方法,通过重写该方法打印输出可以证明)
下面可以通过几个例子验证下是否成功:
简单写一个controller
TestController.java
package com.loger.controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* @author wbs
* Description :
*/
@RestController
@RequestMapping(value = "/test")
public class TestController {
@PostMapping(value = "/xss")
public Object test(String name) {
System.out.println(name);
return name;
}
@PostMapping(value = "/json")
public Object testJSON(@RequestBody Param param) {
return param;
}
@GetMapping(value = "/query")
public Object testQuery(String q){
return q;
}
@PostMapping(value = "/upload")
public Object upload(MultipartFile file){
System.out.println(file.getOriginalFilename());
return "OK";
}
}
下面通过postman测试下效果:



SpringBoot过滤XSS脚本攻击的更多相关文章
- 【快学SpringBoot】过滤XSS脚本攻击(包括json格式)
若图片查看异常,请前往掘金查看:https://juejin.im/post/5d079e555188251ad81a28d9 XSS攻击是什么 XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cas ...
- xss脚本攻击
xss脚本攻击不仅仅只是alert(1)就算完了,xss脚本攻击真正的用处是盗取普通用户的cookie,或者盗取管理员的cookie. xss分类(类型): 1. 反射型xss2. 存储型xss3. ...
- XSS脚本攻击漫谈
XSS跨站脚本攻击一直都被认为是客户端 Web安全中最主流的攻击方式.因为 Web环境的复杂性以及 XSS跨站脚本攻击的多变性,使得该类型攻击很难彻底解决.那么,XSS跨站脚本攻击具体攻击行为是什 ...
- JAVA覆写Request过滤XSS跨站脚本攻击
注:本文非本人原著. demo的地址:链接:http://pan.baidu.com/s/1miEmHMo 密码:k5ca 如何过滤Xss跨站脚本攻击,我想,Xss跨站脚本攻击令人为之头疼.为什么呢. ...
- 第二百六十五节,xss脚本攻击介绍
xss脚本攻击介绍 Cross-Site Scripting(XSS)是一类出现在 web 应用程序上的安全弱点,攻击者可以通过 XSS 插入一 些代码,使得访问页面的其他用户都可以看到,XSS 通常 ...
- 给springboot增加XSS跨站脚本攻击防护功能
XSS原理 xss攻击的原理是利用前后端校验不严格,用户将攻击代码植入到数据中提交到了后台,当这些数据在网页上被其他用户查看的时候触发攻击 举例:用户提交表单时把地址写成:山东省济南市<scri ...
- 防止xss(脚本攻击)的方法之过滤器
一 什么是脚本注入 概念我就不说了 直接百度一份 XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中.比如这些代码包括HTML代码和客户端 ...
- Java过滤XSS脚本, 可通过Appscan扫描
项目中有时会需要把一些报错或者解决方案直接返回给前端, 如果直接返回原字符串, 可能会被恶意传参来实现xss注入. 例如常规业务访问一个页面读取文件&file=sdf.cpt, 如果文件不存在 ...
- Fortify漏洞之Cross-Site Scripting(XSS 跨站脚本攻击)
书接上文,继续对Fortify漏洞进行总结,本篇主要针对XSS跨站脚步攻击漏洞进行总结,如下: 1.Cross-Site Scripting(XSS 跨站脚本攻击) 1.1.产生原因: 1. 数据通过 ...
随机推荐
- python测试开发django-43.xadmin添加小组件报错解决
前言 xadmin首页上有个添加小组件按钮,打开的时候会报错“render() got an unexpected keyword argument 'renderer'”环境:python3.6dj ...
- 安装JDK(Windows)
安装JDK java 安装JDK 下载JDK并安装 配置环境变量 变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1.8.0_144 (jdk安装路径) 变量名: ...
- CodeCombat第一关:KITHGARD地牢之KITHGARD精通
https://www.cnblogs.com/OctoptusLian/p/7397602.html https://www.jianshu.com/p/065581a84879 https://w ...
- c#在WinForm和WebForm中根据控件和属性名获取控件属性值
在WinForm中开发的过程中,所有继承了Control控件,在使用多线程的时候,就需要通过一个通用的方法来设置界面上的控件的属性. delegate void DelegateSetControl( ...
- Topcoder10566 IncreasingNumber
IncreasingNumber 一个数是Increasing当且仅当它的十进制表示是不降的,\(1123579\). 求 \(n\) 位不降十进制数中被 \(d\) 整除的有多少个. \(n\leq ...
- 用Queue控制python多线程并发数量
python多线程如果不进行并发数量控制,在启动线程数量多到一定程度后,会造成线程无法启动的错误. 下面介绍用Queue控制多线程并发数量的方法(python3). # -*- coding: utf ...
- 使用Simian进行重复代码检测
一.概述 Simian是一个可跨平台使用的重复代码检测工具,有商用和免费两种使用渠道,官方网址为:http://www.harukizaemon.com/simian/installation.htm ...
- Django rest_fram_work API View序列化
APIview 单表的GET和POST: 视图 查询所有: class PublishView(APIView): # 查询数据 def get(self, request): # first inq ...
- [bzoj 4176] Lucas的数论 (杜教筛 + 莫比乌斯反演)
题面 设d(x)d(x)d(x)为xxx的约数个数,给定NNN,求 ∑i=1N∑j=1Nd(ij)\sum^{N}_{i=1}\sum^{N}_{j=1} d(ij)i=1∑Nj=1∑Nd(ij) ...
- 做勇敢女孩 https://www.bilibili.com/video/av14346123?from=search&seid=14078047355739050009
So a few years ago, I did something really brave, or some would say really stupid. I ran for congres ...