手写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整合XssFilter,Jsoup等实现请求参数的过滤,处理Xss攻击及sql注入