XSS最为常见的处理方式是转义特殊字符,后端程序在接受任何用户输入的参数时都应当优先考虑是否会存在XSS攻击。
4.1 htmlspecialchars
在PHP中通常会使用htmlspecialchars函数会将一些可能有攻击威胁的字符串转义为html实体编码,这样可以有效的避免XSS攻击。
示例 - htmlspecialchars 转义:
| 字符 | 替换后 |
|---|---|
& (& 符号) |
& |
" (双引号) |
" |
' (单引号) |
'或者' |
< (小于) |
< |
> (大于) |
> |
在Java中虽然没有内置如此简单方便的函数,但是我们可以通过字符串替换的方式实现类似htmlspecialchars函数的功能。
/*** 实现htmlSpecialChars函数把一些预定义的字符转换为HTML实体编码** @param content 输入的字符串内容* @return HTML实体化转义后的字符串*/public static String htmlSpecialChars(String content) {if (content == null) {return null;}char[] charArray = content.toCharArray();StringBuilder sb = new StringBuilder();for (char c : charArray) {switch (c) {case '&':sb.append("&");break;case '"':sb.append(""");break;case '\'':sb.append("'");break;case '<':sb.append("<");break;case '>':sb.append(">");break;default:sb.append(c);break;}}return sb.toString();}
在存储或者输出请求参数的时候使用该方法过滤即可实现XSS防御。
4.2 全局的XSSFilter
package com.anbai.sec.vuls.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.IOException;public class XSSFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;// 创建HttpServletRequestWrapper,包装原HttpServletRequest对象,示例程序只重写了getParameter方法,// 应当考虑如何过滤:getParameter、getParameterValues、getParameterMap、getInputStream、getReaderHttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {public String getParameter(String name) {// 获取参数值String value = super.getParameter(name);// 简单转义参数值中的特殊字符return value.replace("&", "&").replace("<", "<").replace("'", "'");}};chain.doFilter(requestWrapper, resp);}@Overridepublic void destroy() {}}
web.xml添加XSSFilter过滤器:
<!-- XSS过滤器 --><filter><filter-name>XSSFilter</filter-name><filter-class>com.anbai.sec.vuls.filter.XSSFilter</filter-class></filter><filter-mapping><filter-name>XSSFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
请求XSS示例程序:http://localhost:8000/modules/servlet/xss.jsp?input=%3Cscript%3Ealert(%27xss%27);%3C/script%3E;%3C/script%3E)
经过全局过滤器转义后的参数就不会再带有XSS攻击能力了。
4.3 RASP XSS攻击防御
RASP可以实现类似于全局XSSFilter的请求参数过滤功能,比较稳定的一种方式是Hook到javax.servlet.ServletRequest接口的实现类的getParameter/getParameterValues/getParameterMap等核心方法,在该方法return之后插入RASP的检测代码。这种实现方案虽然麻烦,但是可以避免触发Http请求参数解析问题(Web应用无法获取getInputStream和乱码等问题)。
示例 - RASP对getParameter返回值Hook示例:
反射型的XSS防御相对来说比较简单,直接禁止GET参数中出现<>标签,只要出现就理解拦截,如:
http://localhost:8000/modules/servlet/xss.jsp?input=<script>alert('xss');</script>
过滤或拦截掉<>后input参数就不再具有攻击性了。
但是POST请求的XSS参数就没有那么容易过滤了,为了兼顾业务,不能简单的使用htmlSpecialChars的方式直接转义特殊字符,因为很多时候应用程序是必须支持HTML标签的(如:<img>、<h1>等)。RASP在防御XSS攻击的时候应当尽可能的保证用户的正常业务不受影响,否则可能导致用户无法业务流程阻塞或崩溃。
为了支持一些常用的HTML标签和HTML标签属性,RASP可以通过词法解析的方式,将传入的字符串参数值解析成HTML片段,然后分析其中的标签和属性是否合法即可。
4.4 RASP XSS防御能力测试
4.4.1 恶意的HTML标签属性XSS测试
示例 - 提交带有XSS攻击的Payload:
<img src='1.jpg' width='10px' height='10px' onerror='alert(/xss/);' />
请求示例地址:http://localhost:8000/modules/servlet/guestbook.jsp,并填写XSS攻击代码,如下图:
RASP能够正确识别并拦截XSS攻击:
4.4.2 XSS富文本检测测试
RASP如果要实现精确的XSS检测能力就必须能够正确的识别出用户传入的数据到底是否合法,经过HTML词法分析后RASP能够正确认识用户传入的参数值是否是包含了恶意的HTML标签或者属性。
示例 - 用户在留言板中带图片回复:
示例 - 用户在留言板中回复被注释的HTML片段:

经测试,RASP对XSS攻击防御能力正常,能够识别合法的HTML和javascript代码(DOM类XSS占不支持)。
