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

一、XSS攻击

百度百科.
XSS攻击通常指的是通过利用网页开发时留下的<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.4.0</version> </dependency>

三、请求定义包装类

我们平时写Web项目遇到的HttpservletRequest,它其实是个接口。如果我们想要重新定义请求类,扩展这个接口是最不应该的。因为HttpservletRequest接口中抽象方法太多了,我们逐一实现起来太耗费时间。所以我们应该挑选一个简单一点的自定义请求类的方式。那就是继承HttpServletRequestwrapper父类。
JavaEE只是一个标准,具体的实现由各家应用服务器厂商来完成。比如说Tomcat在实现servlet规范的时候,就自定义了HttpservletRequest接口的实现类。同时JavaEE规范还定义了HttpServletRequestwrapper,这个类是请求类的包装类,用上了装饰器模式。不得不说这里用到的设计模式真的非常棒,无论各家应用服务器厂商怎么去实现HttpServletRequest接口,用户想要自定义请求,只需要继承HttpServletRequestwrapper,对应覆盖某个方法即可,然后把请求传入请求包装类,装饰器模式就会替代请求对象中对应的某个方法。用户的代码和服务器厂商的代码完全解耦,我们不用关心HttpServletRequest接口是怎么实现的,借助于包装类我们可以随意修改请求中的方法。
SpringBoot 项目添加抵御跨站防御脚本(XSS)攻击功能

 public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {      public XssHttpServletRequestWrapper(HttpServletRequest request) {         super(request);     }      @Override     public String getParameter(String name) {         String value = super.getParameter(name);         if (!StrUtil.hasEmpty(value)) {             value = HtmlUtil.filter(value);         }         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();         Map<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();         StringBuffer body = new StringBuffer();         InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));         BufferedReader buffer = new BufferedReader(reader);         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 HashMap(map.size());         for (String key : map.keySet()) {             Object val = map.get(key);             if (map.get(key) instanceof String) {                 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 listener) {             }         };     }  }  

四、创建过滤器,把所用请求对象传入包装类

为了让刚刚定义的包装类生效,我们还要在 com.example .emos.wx.config.xss中创建xssFilter过滤器。过滤器拦截所有请求,然后把请求传入包装类,这样包装类就能覆盖所有请求的参数方法,用户从请求中获得数据,全都经过转义。

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 {     }      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)             throws IOException, ServletException {         XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(                 (HttpServletRequest) request);         chain.doFilter(xssRequest, response);     }      @Override     public void destroy() {     } } 

五、给主类添加注解

给SpringBoot主类添加@servletcomponentscan注解。
SpringBoot 项目添加抵御跨站防御脚本(XSS)攻击功能

六、测试拦截XSS脚本

我是通过传入一段<script>alert("xss脚本攻击")</script>脚本, 看返回结果是否可以将其中的html标签过滤掉 

测试结果:
SpringBoot 项目添加抵御跨站防御脚本(XSS)攻击功能
如上图所述,参数中的标签被过滤掉,返回的是去掉标签的字符!

版权声明:玥玥 发表于 2021-05-09 21:18:33。
转载请注明:SpringBoot 项目添加抵御跨站防御脚本(XSS)攻击功能 | 女黑客导航