一、XSS攻击的危害
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、VBScript、ActiveX、Flash或者甚至是普通的HTML。攻击成功后,
攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
例如用户在发帖或者注册的时候,在文本框中输入,这段代码如果不经过转义处理,而直接保存到数据库。将来视图层渲染HTML的时候,把这段代码输出到页面上,那么
二、导入依赖库
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.0</version>
</dependency>
三、定义请求包装类
package com.example.emos.wx.config.xss;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;
import javax.print.DocFlavor;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class XssHttpServeletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServeletRequestWrapper(HttpServletRequest request){
super(request);
}
@Override
public String getParameter(String name){
String value = super.getParameter(name); //获取请求中的原始数据
if(!StrUtil.hasEmpty(value)){ //数据不为空
value = HtmlUtil.filter(value); //把数据做转义,把html、script标签去掉,变成普通的文本
}
return value;
}
/**转义数组中的数据*/
@Override
public String[] getParameterValues(String name){
String[] values = super.getParameterValues(name);
if(values != null){
for(int i=0;i<values.length;i++){
String value = values[i];
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
}
return values;
}
@Override
public Map<String, String[]> getParameterMap(){
Map<String,String[]> parameters = super.getParameterMap();
LinkedHashMap<String,String[]> map = new LinkedHashMap();
if(parameters != null){
for(String key:parameters.keySet()){
String[] values = parameters.get(key);
for(int i=0;i<values.length;i++){
String value = values[i];
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
map.put(key,values);
}
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public ServletInputStream getInputStream() throws IOException{
InputStream in = super.getInputStream();
InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
BufferedReader buffer = new BufferedReader(reader);
StringBuffer body = new StringBuffer();
String line = buffer.readLine();
while (line != null){
body.append(line);
line = buffer.readLine();
}
buffer.close();
reader.close();
in.close();
Map<String,Object> map = JSONUtil.parseObj(body.toString());
Map<String,Object> resultMap = new LinkedHashMap<>();
for(String key : map.keySet()){
Object val = map.get(key);
if(map.get(key) instanceof String){
if(!StrUtil.hasEmpty(val.toString())){
resultMap.put(key, HtmlUtil.filter(val.toString()));
}
}else{
resultMap.put(key, val);
}
}
String str = JSONUtil.toJsonStr(resultMap);
final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bain.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
四、创建过滤器,把所有请求对象传入包装类
package com.example.emos.wx.config.xss;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = "/*") //拦截请求的路径
public class XssFilter implements Filter {
public void init(FilterConfig config) throws ServletException{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
XssHttpServeletRequestWrapper wrapper = new XssHttpServeletRequestWrapper((HttpServletRequest) request);
chain.doFilter(wrapper,response);
}
@Override
public void destroy() {
}
}
五、给主类添加注解
给SpringBoot主类添加@ServletComponentScan
注解
六、测试拦截XSS脚本
测试controller
@RestController
@RequestMapping("/test")
@Api("测试Web接口")
public class TestController {
@PostMapping("/sayHello")
@ApiOperation("最简单的测试方法")
public R sayHello(@Valid @RequestBody TestSayHelloForm form){
return R.ok().put("message","Hello,"+form.getName());
}
}
@ApiModel
@Data
public class TestSayHelloForm {
@NotBlank
private String name;
}
在Swagger中执行sayHello()方法,向name属性传入<script>alert(123456)</script>
观察返回结果