spring mvc 防止xss攻击

在网上查询了一些方法:

1.写一个过滤器和一个HttpServletRequestWrapper 并重写他的getParameterValues 和 getParameter方法,这个方法是可行的但是对@RequsetBody 参数无效

针对Spring MVC中的@RequestParam获取的参数,走的是getParameterValues()方法。
 

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 {

    public void init(FilterConfig config) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request);
        chain.doFilter(xssRequest, response);
    }

    public void destroy() {}
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    HttpServletRequest orgRequest = null;

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
    }
    /**
     * 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
     * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
     * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
     */
    @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] = xssEncode(values[i]);
         }
        return encodedValues;
      }
    
    
    @Override
    public String getParameter(String name) {
    	
        String value = super.getParameter(xssEncode(name));
        System.out.println("before name:"+name +"   value:"+value);
        if (value != null) {
            value = xssEncode(value);
        }
        System.out.println("after name:"+name +"   value:"+value);
        return value;
    }
    /**
     * 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
     * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
     * getHeaderNames 也可能需要覆盖
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(xssEncode(name));
        if (value != null) {
            value = xssEncode(value);
        }
        return value;
    }
    /**
     * 将容易引起xss漏洞的半角字符直接替换成全角字符
     *
     * @param s
     * @return
     */
    private static String xssEncode(String s) {
        if (s == null || s.isEmpty()) {
            return s;
        }
        StringBuilder sb = new StringBuilder(s.length() + 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 '%':    // < 字符的 URL 编码形式表示的 ASCII 字符(十六进制格式) 是: %3c
                processUrlEncoder(sb, s, i);
                break;
            default:
                sb.append(c);
                break;
            }
        }
        return sb.toString();
    }
    public static void processUrlEncoder(StringBuilder sb, String s, int index){
        if(s.length() >= index + 2){
            if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'c' || s.charAt(index+2) == 'C')){    // %3c, %3C
                sb.append('<');
                return;
            }
            if(s.charAt(index+1) == '6' && s.charAt(index+2) == '0'){    // %3c (0x3c=60)
                sb.append('<');
                return;
            }            
            if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'e' || s.charAt(index+2) == 'E')){    // %3e, %3E
                sb.append('>');
                return;
            }
            if(s.charAt(index+1) == '6' && s.charAt(index+2) == '2'){    // %3e (0x3e=62)
                sb.append('>');
                return;
            }
        }
        sb.append(s.charAt(index));
    }
    /**
     * 获取最原始的request
     *
     * @return
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }
    /**
     * 获取最原始的request的静态方法
     *
     * @return
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
        if (req instanceof XssHttpServletRequestWrapper) {
            return ((XssHttpServletRequestWrapper) req).getOrgRequest();
        }
        return req;
    }
    
    
}
<filter>
    <filter-name>XssFilter</filter-name>
    <filter-class>com.glodio.filter.XssFilter</filter-class>
    
   
  </filter>
  <filter-mapping>
    <filter-name>XssFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

这种是把特殊字符串全部都换掉

2 使用spring 带的StringEscapeUtils 把特殊字段进行转义

  System.out.println(StringEscapeUtils.escapeHtml("<a>dddd</a>"));
  System.out.println(StringEscapeUtils.escapeHtml("<script>alert('111')</script>"));

//输出结果

&lt;a&gt;dddd&lt;/a&gt;
&lt;script&gt;alert('111')&lt;/script&gt;

直接对字段进行转义。

@InitBinder
protected void initBinder(WebDataBinder binder) {
	// String类型转换,将所有传递进来的String进行HTML编码,防止XSS攻击
	binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
		@Override
		public void setAsText(String text) {
			setValue(text == null ? null : StringEscapeUtils.escapeHtml(text.trim()));
		}
		@Override
		public String getAsText() {
			Object value = getValue();
			return value != null ? value.toString() : "";
		}
	});
}

根据需要可以选择一种。

扫描二维码关注公众号,回复: 2411289 查看本文章

猜你喜欢

转载自blog.csdn.net/hyhanyu/article/details/81097641