赞
踩
近期做的一个项目进行渗透测试,检测代码存在存储型Xss漏洞。例如在界面文本域输入<h2>12345</h2>、<script>alter(12345)</script>这样的值,如果程序未进行处理,会存储至数据库。下次回显会出现异常界面或弹出异常框,如果进行恶意攻击,可能后果不堪设想。
网上搜集的大部分代码都是使用过滤器,并对请求数据进行过滤,重写getParameter(String str)方法。因项目使用的数据结构并非字符串,而是封装的Map,这种方法无法实现该项目的具体需求。反编译看了jar文件,其中有方法getParameterMap()可以使用,只需进行重写即可。
实现该功能,分三步:
第一步,编写过滤器,实现Filter接口,代码如下:
- package com.xx;
-
- import java.io.IOException;
-
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
-
- public class XSSFilter implements Filter {
-
- @Override
- public void init(FilterConfig arg0) throws ServletException {
- }
-
- @Override
- public void destroy() {
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- chain.doFilter(new XssRequestWrappers((HttpServletRequest) request), response);
-
- }
-
- }
第二步,继承HttpServletRequestWrapper,重写方法getParameterMap,代码如下:
- package com.xx;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
-
- import org.springframework.util.StringUtils;
- import org.springframework.web.multipart.MultipartHttpServletRequest;
- import org.springframework.web.multipart.commons.CommonsMultipartResolver;
- public class XssRequestWrappers extends HttpServletRequestWrapper {
- private CommonsMultipartResolver multiparResolver = new CommonsMultipartResolver();
-
- public XssRequestWrappers(HttpServletRequest request) {
- super(request);
-
- String type = request.getHeader("Content-Type");
- if (!StringUtils.isEmpty(type) && type.contains("multipart/form-data")) {
- MultipartHttpServletRequest multipartHttpServletRequest = multiparResolver.resolveMultipart(request);
- Map<String, String[]> stringMap = multipartHttpServletRequest.getParameterMap();
- if (!stringMap.isEmpty()) {
- for (String key : stringMap.keySet()) {
- String value = multipartHttpServletRequest.getParameter(key);
- XSSUtils.stripXSS(key);
- XSSUtils.stripXSS(value);
- }
- }
- super.setRequest(multipartHttpServletRequest);
- }
- }
-
- @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] = XSSUtil.stripXSS(values[i]);
- }
- return encodedValues;
- }
-
- @Override
- public String getParameter(String parameter) {
- String value = super.getParameter(parameter);
- return XSSUtils.stripXSS(value);
- }
-
- @Override
- public String getHeader(String name) {
- String value = super.getHeader(name);
- return XSSUtils.stripXSS(value);
- }
-
- @Override
- public Map<String, String[]> getParameterMap() {
- Map<String, String[]> map1 = super.getParameterMap();
- Map<String, String[]> escapseMap = new HashMap<String, String[]>();
- Set<String> keys = map1.keySet();
- for (String key : keys) {
- String[] valArr = map1.get(key);
- if (valArr != null && valArr.length > 0) {
- String[] escapseValArr = new String[valArr.length];
- for (int i = 0; i < valArr.length; i++) {
- String escapseVal = XSSUtils.striptXSS(valArr[i]);
- escapseValArr[i] = escapseVal;
- }
- escapseMap.put(key, escapseValArr);
- }
- }
-
- return escapseMap;
- }
-
- }
此处写了一个工具类XSSUtils,现在的做法是替换成空字符,CSDN的是进行转义,比如文字开头的"<"转成<。代码如下:
- package com.xx;
-
- import java.util.regex.Pattern;
-
- public class XSSUtils {
-
- public static String striptXSS(String value) {
- if (value != null) {
-
- value = value.replaceAll("", "");
- Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
- value = scriptPattern.matcher(value).replaceAll("");
- scriptPattern = Pattern.compile(".*<.*", Pattern.CASE_INSENSITIVE );
- value = scriptPattern.matcher(value).replaceAll("");
- }
- return value;
- }
-
-
- }
第三步,web.xml注册过滤器,代码如下:
- <filter>
- <filter-name>XssFilter</filter-name>
- <filter-class>com.xx.XSSFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>XssFilter</filter-name>
- <url-pattern>*.do</url-pattern>
- </filter-mapping>
代码完。此代码贴在这里的没加注释,需要使用的,最好在项目中添加注释。利人利己。
扩展:后期可对这个功能进行扩展,做成可配置的,比如请求报文的头文件无需过滤;对不同的项目使用的不同的数据结构进行参数化;对这个需要过滤的文件格式进行参数配置,方便生产环境的突发意外情况。
思考:是否会有一种在web.xml里配置即可解决该问题的方法,类似CharacterEncodingFilter这样的,便于开发者操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。