一、问题背景
使用 SpringBoot 的项目出现了跨站脚本漏洞(XSS)问题。
二、解决方案
步骤如下:
1、添加maven依赖
在 pom.xml 文件中,增加如下依赖:
<dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-servlet-api</artifactId><version>8.0.36</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency>
2、新增 XSSFilter.java
在 config 目录下增加 XSSFilter.java,用于对请求接口进行过滤。
代码如下:
importjavax.servlet.*;importjavax.servlet.annotation.WebFilter;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;@WebFilter(filterName="XSSFilter", urlPatterns="/*")publicclassXSSFilterimplementsFilter{FilterConfig filterConfig =null;@Overridepublicvoidinit(FilterConfig filterConfig)throwsServletException{this.filterConfig = filterConfig;}@OverridepublicvoiddoFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throwsIOException,ServletException{
filterChain.doFilter(newXssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);}@Overridepublicvoiddestroy(){this.filterConfig =null;}}
3、新增 XssHttpServletRequestWrapper.java
在 config 目录下,新增 XssHttpServletRequestWrapper.java,用于对请求参数进行预处理和解析。
代码如下:
importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.nio.charset.Charset;importjava.util.HashMap;importjava.util.Map;publicclassXssHttpServletRequestWrapperextendsHttpServletRequestWrapper{publicXssHttpServletRequestWrapper(HttpServletRequest request){super(request);}@OverridepublicString[]getParameterValues(String parameter){String[] values =super.getParameterValues(parameter);if(values==null){returnnull;}int count = values.length;String[] encodedValues =newString[count];for(int i =0; i < count; i++){
encodedValues[i]=cleanXSS(values[i]);}return encodedValues;}@OverridepublicStringgetParameter(String parameter){String value =super.getParameter(parameter);if(value !=null){returncleanXSS(value);}returnnull;}/**
* 对 application/x-www-form-urlencoded 格式的POST请求参数,进行 cleanXSS解析
* @return cleanXSS解析后的参数
*/@OverridepublicMap<String,String[]>getParameterMap(){Map<String,String[]> values =super.getParameterMap();if(values ==null){returnnull;}Map<String,String[]> result =newHashMap<>();for(String key : values.keySet()){String encodedKey =cleanXSS(key);int count = values.get(key).length;String[] encodedValues =newString[count];for(int i =0; i < count; i++){
encodedValues[i]=cleanXSS(values.get(key)[i]);}
result.put(encodedKey, encodedValues);}return result;}@OverridepublicStringgetHeader(String name){String value =super.getHeader(name);if(value ==null)returnnull;returncleanXSS(value);}privatestaticStringcleanXSS(String value){
value = value.replaceAll("<","<").replaceAll(">",">");
value = value.replaceAll("%3C","<").replaceAll("%3E",">");
value = value.replaceAll("\\(","(").replaceAll("\\)",")");
value = value.replaceAll("%28","(").replaceAll("%29",")");
value = value.replaceAll("'","'");
value = value.replaceAll("eval\\((.*)\\)","");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']","\"\"");
value = value.replaceAll("script","");return value;}@OverridepublicServletInputStreamgetInputStream()throwsIOException{finalByteArrayInputStream bais =newByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());returnnewServletInputStream(){@Overridepublicintread()throwsIOException{return bais.read();}@OverridepublicbooleanisFinished(){returnfalse;}@OverridepublicbooleanisReady(){returnfalse;}@OverridepublicvoidsetReadListener(ReadListener readListener){}};}publicStringinputHandlers(ServletInputStream servletInputStream){StringBuilder sb =newStringBuilder();BufferedReader reader =null;try{
reader =newBufferedReader(newInputStreamReader(servletInputStream,Charset.forName("UTF-8")));String line ="";while((line = reader.readLine())!=null){
sb.append(line);}}catch(IOException e){
e.printStackTrace();}finally{if(servletInputStream !=null){try{
servletInputStream.close();}catch(IOException e){
e.printStackTrace();}}if(reader !=null){try{
reader.close();}catch(IOException e){
e.printStackTrace();}}}returncleanXSS(sb.toString ());}}
4、添加注解 @ServletComponentScan
在 XXXApplication.java 的类名上方,用于扫描配置类。添加注解如下:
@ServletComponentScan("com.XXX.config")
示例如下:
版权归原作者 龙凌云 所有, 如有侵权,请联系我们删除。