一. XSS 介绍
网站中包含大量的动态内容以提高用户体验,比过去要复杂得多。所谓动态内容,就是根据用户环境和需要,Web 应用程序能够输出相应的内容。动态站点会受到一种名为 “跨站脚本攻击”(Cross Site Scripting, 安全专家们通常将其缩写成 XSS, 原本应当是 css,但为了和层叠样式表(Cascading Style Sheet,CSS )有所区分,故称 XSS)的威胁,而静态站点则完全不受其影响。
二. 攻击类型
- 持久型跨站:最直接的危害类型,跨站代码存储在服务器(数据库)。
- 非持久型跨站:反射型跨站脚本漏洞,最普遍的类型。用户访问服务器 - 跨站链接 - 返回跨站代码。
- DOM 跨站(DOM XSS):DOM(document object model 文档对象模型),客户端脚本处理逻辑导致的安全问题。
关于 XSS 的更多信息,具体可以参考百度百科。
三. 解决方案
1. 自定义 HttpServletRequestWrapper
/*** XSS过滤处理类,用于HTTP请求中特殊字符的转换,解决跨站点等攻击** @date 2020-03-16* @author DaiQi*/public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {/*** 请求*/private HttpServletRequest xssRequest = null;public XssHttpServletRequestWrapper(HttpServletRequest request) {super(request);xssRequest = request;}/*** 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖* @param name 名称* @return 返回字符串*/public String getParameter(String name) {String value = super.getParameter(XssUtil.xssEncode(name));if (value != null) {value = XssUtil.xssEncode(value);}return value;}/*** 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>* getHeaderNames 也可能需要覆盖* @param name 名称* @return 返回字符串*/public String getHeader(String name) {String value = super.getHeader(XssUtil.xssEncode(name));if (!StringUtils.isEmpty(value)) {//方法一:自定义XSS过滤工具类value = XssUtil.xssEncode(value);//方法二:转义为html格式//org.apache.commons.lang3下的StringEscapeUtils已经过时了//可以使用org.apache.commons.text.StringEscapeUtils 进行替换//value = org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(value);}return value;}/*** 获取最原始的request的静态方法* @param req req`在这里插入代码片`* @return HttpServletRequest*/public static HttpServletRequest getOrgRequest(HttpServletRequest req) {if (req instanceof XssHttpServletRequestWrapper) {return ((XssHttpServletRequestWrapper) req).xssRequest;}return req;}}
2. 自定义过滤器
/*** XSS过滤器** @date 2020-03-16* @author DaiQi*/@Order(2)@WebFilter(filterName = "xssFilter", urlPatterns = "/*")public class XssFilter extends OncePerRequestFilter {/*** 内部过滤** @param request* @param response* @param filterChain* @throws ServletException* @throws IOException*/@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);filterChain.doFilter(xssRequest, response);}}
3.XssUtil
/*** XSS工具类*/public class XssUtil {/*** 常量16*/public static final int NUM_16 = 16;/*** 私有构造函数*/private XssUtil() {}/*** 将容易引起xss漏洞的半角字符直接替换成全角字符** @param s 原字符串* @return 替换后的字符串*/public static String xssEncode(String s) {if (s == null || "".equals(s)) {return s;}StringBuilder sb = new StringBuilder(s.length() + NUM_16);for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);switch (c) {case '>':sb.append('>');// 全角大于号break;case '<':sb.append('<');// 全角小于号break;case '\'':sb.append('‘');// 全角单引号break;case '\"':sb.append('“');// 全角双引号break;case '&':sb.append('&');// 全角与逻辑符break;case '%':sb.append('%');// 全角百分号break;case '+':sb.append("+");// 全角加号break;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();}}
