关于XSS漏洞修复
XSS即恶意脚本攻击漏洞,详细的描述网上介绍的很详细。我说一下自己在工作中对这种漏洞的修复方案,仅供参考。
第一阶段:使用ESAPI
这是一个Apache开发的安全组件,主要用于解决SQL注入和恶意脚本注入。
使用ESAPI防止XSS攻击时,首先应当配置过滤器(注意在过滤器中chain.doFilter(..)方法中的Request对象进行包装,在包装类中对请求参数进行筛选操作);其次将过滤器注册到web.xml文件中;最后配置Request的包装类,在其中对请求信息进行过滤。
1 import java.io.IOException; 2 import javax.servlet.Filter; 3 import javax.servlet.FilterChain; 4 import javax.servlet.FilterConfig; 5 import javax.servlet.ServletException; 6 import javax.servlet.ServletRequest; 7 import javax.servlet.ServletResponse; 8 import javax.servlet.http.HttpServletRequest; 9 10 /* 11 *配置XSS过滤器 12 */ 13 public class XSSFilter implements Filter { 14 @Override 15 public void init(FilterConfig filterConfig) throws ServletException { 16 } 17 @Override 18 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 19 throws IOException, ServletException { 20 chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response); 21 } 22 @Override 23 public void destroy() { 24 } 25 }
1 <!-- XSS攻击防范 --> 2 <filter> 3 <filter-name>XSSFilter</filter-name> 4 <filter-class>过滤器全类名</filter-class> 5 </filter> 6 <filter-mapping> 7 <filter-name>XSSFilter</filter-name> 8 <url-pattern>/*</url-pattern> 9 <dispatcher>REQUEST</dispatcher> 10 <dispatcher>FORWARD</dispatcher> 11 </filter-mapping>
1 import java.net.URLDecoder; 2 import java.util.regex.Pattern; 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletRequestWrapper; 5 import org.owasp.esapi.ESAPI; 6 7 /* 8 * 对传入参数进行校验 9 */ 10 public class XSSRequestWrapper extends HttpServletRequestWrapper { 11 public XSSRequestWrapper(HttpServletRequest servletRequest) { 12 super(servletRequest); 13 } 14 @Override 15 public String[] getParameterValues(String parameter) { 16 String[] values = super.getParameterValues(parameter); 17 if (values == null) { 18 return null; 19 } 20 int count = values.length; 21 String[] encodedValues = new String[count]; 22 for (int i = 0; i < count; i++) { 23 encodedValues[i] = stripXSS(values[i]); 24 } 25 return encodedValues; 26 } 27 @Override 28 public String getParameter(String parameter) { 29 String value = super.getParameter(parameter); 30 return stripXSS(value); 31 } 32 @Override 33 public String getHeader(String name) { 34 String value = super.getHeader(name); 35 return stripXSS(value); 36 } 37 38 private String stripXSS(String value) { 39 if (value != null) { 40 //解析URL编码,防止前台的编码后的参数进入ESAPI过滤后无法正常解码 41 value = URLDecoder.decode(value); 42 // 使用ESAPI的防护功能避免XSS攻击 43 value = ESAPI.encoder().canonicalize(value); 44 // 去除空字符 45 value = value.replaceAll("", ""); 46 // 过滤脚本标签间(如:<script>..</script>)的内容 47 Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); 48 value = scriptPattern.matcher(value).replaceAll(""); 49 //过滤由项目路径(src)直接访问项目资源的行为 50 scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 51 value = scriptPattern.matcher(value).replaceAll(""); 52 scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 53 value = scriptPattern.matcher(value).replaceAll(""); 54 // 过滤单个</script>标签 55 scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); 56 value = scriptPattern.matcher(value).replaceAll(""); 57 // 过滤单个<script ...> 标签 58 scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 59 value = scriptPattern.matcher(value).replaceAll(""); 60 // 过滤 eval(...) 表达式 61 scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 62 value = scriptPattern.matcher(value).replaceAll(""); 63 // 过滤expression(...) 表达式 64 scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 65 value = scriptPattern.matcher(value).replaceAll(""); 66 // 过滤javascript:表达式攻击 67 scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); 68 value = scriptPattern.matcher(value).replaceAll(""); 69 // 过滤vbscript:表达式攻击 70 scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); 71 value = scriptPattern.matcher(value).replaceAll(""); 72 // 过滤onload=事件 73 scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 74 value = scriptPattern.matcher(value).replaceAll(""); 75 } 76 return value; 77 } 78 }
注意:开启ESAPI的防护功能时(value = ESAPI.encoder().canonicalize(value);),需要提前对要筛选的值进行URL解码(value = URLDecoder.decode(value);),否则会出现中文乱码。
第二阶段(可选):使用CSF(Content Security Policy)安全策略
CSF是一种白名单防御策略,所有不在名单内的资源都不被信任,有效的防止了通过外部的标签、脚本、JS文件等资源的入侵形式,详情请看http://www.ruanyifeng.com/blog/2016/09/csp.html,我也是在这位大佬的网站上学习的CSF.
使用方式:
1.通过<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">标签将CSP嵌入到页面中。但是这种做法会对所有页面添加一个过滤项,加长了页面的访问时间,降低了用户体验;我加到项目中的时候还出现了某些样式文件加载不全的现象,没有必要不建议这么做。
2.通过使用Nginx配置HTTP 头信息的Content-Security-Policy的字段,但是一般的公司都不允许更改Nginx,一旦Nginx做了某种配置,整个项目都受影响,这种方式基本没戏。