手写SpringBoot项目XSS攻击过滤器实现

Posted Yubaba丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写SpringBoot项目XSS攻击过滤器实现相关的知识,希望对你有一定的参考价值。

一、先来个简介

什么是XSS?

百度百科的解释: XSS又叫CSS  (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。

它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的,而在xss攻击中,通过插入恶意脚本,实现对用户游览器的控制,获取用户的一些信息。

二、XSS分类

xss攻击可以分成两种类型:

1.非持久型攻击
2.持久型攻击

非持久型xss攻击:顾名思义,非持久型xss攻击是一次性的,仅对当次的页面访问产生影响。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。

持久型xss攻击:持久型xss,会把攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据一直存在。 

也可以分成三类:

反射型:经过后端,不经过数据库

存储型:经过后端,经过数据库

三、废话不多说直接上代码

先加pom文件加上依赖

1    <dependency>
2             <groupId>org.apache.commons</groupId>
3             <artifactId>commons-text</artifactId>
4             <version>1.4</version>
5    </dependency>

1.首先是要写个过滤器的包装类,这也是实现XSS攻击过滤的核心代码。

  1 package com.hrt.zxxc.fxspg.xss;
  2 
  3 import com.alibaba.fastjson.JSON;
  4 import org.apache.commons.lang3.StringUtils;
  5 import org.apache.commons.text.StringEscapeUtils;
  6 
  7 import javax.servlet.ReadListener;
  8 import javax.servlet.ServletInputStream;
  9 import javax.servlet.http.HttpServletRequest;
 10 import javax.servlet.http.HttpServletRequestWrapper;
 11 import java.io.*;
 12 import java.nio.charset.Charset;
 13 import java.util.HashMap;
 14 import java.util.Map;
 15 
 16 /**
 17  * @program: fxspg
 18  * @description: XSS过滤具体核心代码
 19  * @author: liumingyu
 20  * @date: 2020-01-10 14:28
 21  **/
 22 public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
 23 
 24     /**
 25      * @return
 26      * @Author liumingyu
 27      * @Description //TODO 构造函数,传入参数,执行超类
 28      * @Date 2020/1/10 2:29 下午
 29      * @Param [request]
 30      **/
 31     public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
 32         super(request);
 33     }
 34 
 35     /**
 36      * @return java.lang.String
 37      * @Author liumingyu
 38      * @Description //TODO 重写getParameter方法 ,getParameter方法是直接通过request获得querystring类型的入参调用的方法
 39      * @Date 2020/1/10 2:31 下午
 40      * @Param [name]
 41      **/
 42     @Override
 43     public String getParameter(String name) {
 44         String value = super.getParameter(name);
 45         if (!StringUtils.isEmpty(value)) {
 46             //调用Apache的工具类:StringEscapeUtils.escapeHtml4
 47             value = StringEscapeUtils.escapeHtml4(value);
 48         }
 49         return value;
 50     }
 51 
 52     /**
 53      * @return java.lang.String[]
 54      * @Author liumingyu
 55      * @Description //TODO 重写getParameterValues
 56      * @Date 2020/1/10 2:32 下午
 57      * @Param [name]
 58      **/
 59     @Override
 60     public String[] getParameterValues(String name) {
 61         String[] parameterValues = super.getParameterValues(name);
 62         if (parameterValues == null) {
 63             return null;
 64         }
 65         for (int i = 0; i < parameterValues.length; i++) {
 66             String value = parameterValues[i];
 67             //调用Apache的工具类:StringEscapeUtils.escapeHtml4
 68             parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
 69         }
 70         return parameterValues;
 71     }
 72 
 73     @Override
 74     public String getHeader(String name) {
 75         return StringEscapeUtils.escapeHtml4(super.getHeader(name));
 76     }
 77 
 78     @Override
 79     public String getQueryString() {
 80         return StringEscapeUtils.escapeHtml4(super.getQueryString());
 81     }
 82 
 83     /**
 84      * @return javax.servlet.ServletInputStream
 85      * @Author liumingyu
 86      * @Description //TODO 过滤JSON数据中的XSS攻击
 87      * @Date 2020/1/10 4:58 下午
 88      * @Param []
 89      **/
 90     @Override
 91     public ServletInputStream getInputStream() throws IOException {
 92         //调用方法将流数据return为String
 93         String str = getRequestBody(super.getInputStream());
 94         //如果str为"",则返回0
 95         if ("".equals(str)) {
 96             return new ServletInputStream() {
 97                 @Override
 98                 public int read() throws IOException {
 99                     return 0;
100                 }
101 
102                 @Override
103                 public boolean isFinished() {
104                     return false;
105                 }
106 
107                 @Override
108                 public boolean isReady() {
109                     return false;
110                 }
111 
112                 @Override
113                 public void setReadListener(ReadListener readListener) {
114 
115                 }
116             };
117         }
118         //将数据存放至map
119         Map<String, Object> map = JSON.parseObject(str, Map.class);
120         //声明个存放过滤后数据的hashMap
121         Map<String, Object> resultMap = new HashMap<>(map.size());
122         //开始遍历数据
123         for (String key : map.keySet()) {
124             Object val = map.get(key);
125             //如果key=富文本字段名,就不去过滤
126             if ("content".equals(key)) {
127                 //不过滤
128                 resultMap.put(key, val);
129             } else {
130                 //不为富文本字段才会过滤
131                 if (map.get(key) instanceof String) {
132                     //通过escapeHtml4去过滤
133                     resultMap.put(key, StringEscapeUtils.escapeHtml4(val.toString()));
134                 } else {
135                     //不过滤
136                     resultMap.put(key, val);
137                 }
138             }
139         }
140         str = JSON.toJSONString(resultMap);
141         final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes());
142         return new ServletInputStream() {
143             @Override
144             public int read() throws IOException {
145                 return byteArrayInputStream.read();
146             }
147 
148             @Override
149             public boolean isFinished() {
150                 return false;
151             }
152 
153             @Override
154             public boolean isReady() {
155                 return false;
156             }
157 
158             @Override
159             public void setReadListener(ReadListener readListener) {
160 
161             }
162 
163         };
164     }
165 
166     /**
167      * @return java.lang.String
168      * @Author liumingyu
169      * @Description //TODO 获取JSON数据
170      * @Date 2020/1/10 4:58 下午
171      * @Param [stream]
172      **/
173     private String getRequestBody(InputStream stream) {
174         String line = "";
175         StringBuilder body = new StringBuilder();
176         int counter = 0;
177         // 读取POST提交的数据内容
178         BufferedReader reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
179         try {
180             while ((line = reader.readLine()) != null) {
181                 //拼接读取到的数据
182                 body.append(line);
183                 counter++;
184             }
185         } catch (IOException e) {
186             e.printStackTrace();
187         }
188         if (body == null) {
189             return "";
190         }
191         //最后返回数据
192         return body.toString();
193     }
194 
195 }

2.看到这里你就已经完成了一半了加油!接下来的事情很简单写个过滤器就over 。

 1 package com.hrt.zxxc.fxspg.xss;
 2 
 3 import com.fasterxml.jackson.databind.ObjectMapper;
 4 import com.fasterxml.jackson.databind.module.SimpleModule;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Primary;
 7 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 8 import org.springframework.stereotype.Component;
 9 
10 import javax.servlet.*;
11 import javax.servlet.annotation.WebFilter;
12 import javax.servlet.http.HttpServletRequest;
13 import java.io.IOException;
14 
15 /**
16  * @program: fxspg
17  * @description: XSS过滤器
18  * @author: liumingyu
19  * @date: 2020-01-10 14:36
20  **/
21 
22 @WebFilter
23 @Component
24 public class XssFilter implements Filter {
25 
26     /**
27      * @return void
28      * @Author liumingyu
29      * @Description //TODO 重写init
30      * @Date 2020/1/10 2:38 下午
31      * @Param [filterConfig]
32      **/
33     @Override
34     public void init(FilterConfig filterConfig) throws ServletException {
35 
36     }
37 
38     /**
39      * @return void
40      * @Author liumingyu
41      * @Description //TODO 重写doFilter,将请求进行xss过滤
42      * @Date 2020/1/10 2:41 下午
43      * @Param [servletRequest, servletResponse, filterChain]
44      **/
45     @Override
46     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
47                          FilterChain filterChain) throws IOException, ServletException {
48         //获取请求数据
49         HttpServletRequest req = (HttpServletRequest) servletRequest;
50         //获取请求的url路径
51         String path = ((HttpServletRequest) servletRequest).getServletPath();
52         //声明要被忽略请求的数组
53         String[] exclusionsUrls = {".js", ".gif", ".jpg", ".png", ".css", ".ico"};
54         //遍历忽略的请求数组,若该接口url为忽略的就调用原本的过滤器,不走xss过滤
55         for (String str : exclusionsUrls) {
56             if (path.contains(str)) {
57                 filterChain.doFilter(servletRequest, servletResponse);
58                 return;
59             }
60         }
61         //将请求放入XSS请求包装器中,返回过滤后的值
62         XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
63         filterChain.doFilter(xssRequestWrapper, servletResponse);
64     }
65 
66     @Override
67     public void destroy() {
68 
69     }
70 
71 }

注:上面的注释我都写得比较全了,不过多解释,so easy是不是!

以上是关于手写SpringBoot项目XSS攻击过滤器实现的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot过滤XSS脚本攻击

SpringBoot 项目添加抵御跨站防御脚本(XSS)攻击功能

SpringBoot整合XssFilter,Jsoup等实现请求参数的过滤,处理Xss攻击及sql注入

【快学springboot】15、SpringBoot过滤XSS脚本攻击

SpringBoot使用mica-xss防止Xss攻击

springboot安全组件总结