首页 > 技术文章 > xss攻击防范转义处理

wulm 2021-09-12 14:02 原文

1:xss攻击原理说明

  这里不再详细参数,简单说一下,就是前端提交了可执行的js等脚本,存储到数据库,页面再次加载时获取到该脚本执行了脚本内容就发生了脚本注入。

 

2:处理办法

  转义提交字符

 

3:代码逻辑原理

  利用过滤器,重写参数获取方法,对参数进行转义。

 

4:代码

 

  4.1 xss转义包装类(重写getParameter、getParameterValues、getParameterMap

package com.zxy.product.system.web.converter;

import cn.hutool.core.util.EscapeUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public static final String HEADER_XSS_FILTER = "xssFilter";

    public static final String[] EMPTY_STRING_ARRAY = new String[0];

    /**
     * 安全xss处理,不影响普通标签输出。
     */
    public static final String XSS_FILTER_FULL_ANGLE = "1";
    /**
     * html转义
     */
    public static final String XSS_FILTER_ESCAPE_HTML = "2";


    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request The request to wrap
     * @throws IllegalArgumentException if the request is null
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }


    /**
     * 全角字符转义
     *
     * @param str 待转义
     * @return 转义结果
     * @author wulingming
     * @date 2021/9/9 17:07
     **/
    public static String escapeFullAngle(String str) {
        if (str == null || str.length() == 0) {
            return str;
        } else {
            return str.replace("<", "《").replace(">", "》");
        }
    }

    public static String escapeHtml4(String str) {
        if (str == null || str.length() == 0) {
            return str;
        } else {
            return EscapeUtil.escapeHtml4(str);
        }
    }

    private static String escape(String value) {
        return escape(value, null);
    }

    private static String escape(String value, String headerXssFilter) {
        if (XSS_FILTER_ESCAPE_HTML.equals(headerXssFilter)) {
            //html转义
            return escapeHtml4(value);
        } else {
            //使用Jsoup防止XSS攻击。还有一种方式是hutol(优缺点,部分字符可能不输出)
            return clean(value);
        }
    }


    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value == null || value.length() == 0) {
            return null;
        }
        String headerXssFilter = super.getHeader(HEADER_XSS_FILTER);
        return escape(value, headerXssFilter);
    }


    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values == null || values.length == 0) {
            return values;
        }

        String headerXssFilter = super.getHeader(HEADER_XSS_FILTER);

        return Stream.of(values).map(value -> escape(value, headerXssFilter)).collect(Collectors.toList())
                .toArray(EMPTY_STRING_ARRAY);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameterMap = super.getParameterMap();
        if (parameterMap == null || parameterMap.isEmpty()) {
            return parameterMap;
        }

        String headerXssFilter = super.getHeader(HEADER_XSS_FILTER);

        return parameterMap.keySet().stream().filter(Objects::nonNull)
                .collect(Collectors.toMap(key -> key, key -> {
                    String[] values = parameterMap.get(key);
                    if (values == null || values.length == 0) {
                        return EMPTY_STRING_ARRAY;
                    } else {
                        return Stream.of(values).map(value -> escape(value, headerXssFilter))
                                .collect(Collectors.toList()).toArray(EMPTY_STRING_ARRAY);
                    }
                }));
    }


    /**
     * 使用自带的basicWithImages 白名单
     * 允许的便签有a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span,
     * strike,strong,sub,sup,u,ul,img
     * 以及a标签的href,img标签的src,align,alt,height,width,title属性
     */
    private static final Whitelist whitelist = Whitelist.relaxed();
    /**
     * 配置过滤化参数,不对代码进行格式化
     */
    private static final Document.OutputSettings outputSettings = new Document.OutputSettings()
            .prettyPrint(false);

    static {
        // 富文本编辑时一些样式是使用style来进行实现的,比如红色字体 style="color:red;"
        whitelist.addAttributes(":all", "style");

        //使用相对路径,比如:img标签
        whitelist.preserveRelativeLinks(true);

    }

    /**
     * 安全xss处理,不影响普通标签输出。
     *
     * @param text 原始文本
     * @return 清理后的文本
     * @author wulingming
     **/
    public static String clean(String text) {
        //baseUri可以随便填写,因为使用了相对路径 preserveRelativeLinks(true)
        return Jsoup.clean(text, "https://ilearning.csair.com/", whitelist, outputSettings);
    }

}

 

 

 

  4.2 xss过滤器配置

 

/**
 * xss攻击防范处理
 * @author wulingming
 * @date 2021/9/9 16:32
 **/
@WebFilter(urlPatterns = "/*", filterName = "xssFilter")
public class XssFilter implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

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

    }
}

  4.3 springboot 启动类配置过滤器扫描

@ServletComponentScan

 

getParameter

推荐阅读