本最近项目遇到了一个问题,就是XSS攻击问题,搜索了很多资料。最终实现了符合当前项目的方式:
环境概述
由于,本项目中全部采用的是注入方式,就是没有web.xml的方式,所以和网上找到的在web.xml中配置过滤器方式对我现在的项目并不适用。并且,项目是前后端分离的,也就是前端和后端是完全分开部署的。项目特征是前端传递json类型数据到后端接口,后端接口以
public ResponseEntity create(@RequestBody TUser user) {}
或者
public ResponseEntity list(UserQueryVO userQueryVO) {}
的方式处理数据。
具体实现方法
大体流程:包装request->创建过滤器->添加过滤器
一、创建包装request的类
/** * Created by Angevin. * Date: 2016/12/29 9:49 * description: */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { boolean isUpData = false;//判断是否是上传 上传忽略 public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); String contentType = servletRequest.getContentType (); if (null != contentType) isUpData =contentType.startsWith ("multipart"); } @Override public String[] getParameterValues(String parameter) { String[] values = super.getParameterValues(parameter); if (values==null) { return null; } int count = values.length; String[] encodedValues = new String[count]; for (int i = 0; i < count; i++) { encodedValues[i] = cleanXSS(values[i]); } return encodedValues; } @Override public String getParameter(String parameter) { String value = super.getParameter(parameter); if (value == null) { return null; } return cleanXSS(value); } /** * 获取request的属性时,做xss过滤 */ @Override public Object getAttribute(String name) { Object value = super.getAttribute(name); if (null != value && value instanceof String) { value = cleanXSS((String) value); } return value; } @Override public String getHeader(String name) { String value = super.getHeader(name); if (value == null) return null; return cleanXSS(value); } private static String cleanXSS(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; } @Override public ServletInputStream getInputStream () throws IOException { if (isUpData){ return super.getInputStream (); }else{ final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } } public String inputHandlers(ServletInputStream servletInputStream){ StringBuilder sb = new StringBuilder(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader (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(); } } } return cleanXSS(sb.toString ()); } }
需要注意的是getInputStream()方法的流处理,注解方式获取数据貌似是根据这个流取得的数据。因为super.getInputStream()流只允许读取一次,所以在getInputStream()方法中处理完流数据后返回了一个新的ServletInputStream。另外替换方法里的替换规则,也可以根据实际业务需要进行调整。
二、创建过滤器
/** * Created by Angevin. * Date: 2016/12/29 9:57 * description: */ public class XssFilter implements Filter { FilterConfig filterConfig = null; public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void destroy() { this.filterConfig = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(new XssHttpServletRequestWrapper ( (HttpServletRequest) request), response); } }
三、添加过滤器
由于前面提到的本项目采用的是注入方式,虽然是web项目但并没有web.xml文件所以添加过滤器是实现了WebApplicationInitializer类的方法onStartup(),当然也可以添加拦截器。
public class WebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.addListener(RequestContextListener.class); FilterRegistration.Dynamic XssfilterRegistration = servletContext.addFilter("XssSqlFilter",XssFilter.class); XssfilterRegistration.addMappingForUrlPatterns(EnumSet.of( DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*"); } }
本次添加过滤器处理在没有web.xml文件的情况下防XSS攻击的方法基本也就这样了,期间参考了很多网友的代码,由于参考查看的太多。这里不一一列出,但依然很感谢网友的共享。