Java利用拦截器处理XSS漏洞

Java利用拦截器处理XSS漏洞,第1张

Java利用拦截器处理XSS漏洞

当应用程序的新网页中包含不受信任的、未经恰当验证或转义的数据时,或者 使用可以创建 HTML 或 JavaScript 的浏览器 API 更新现有的网页时,就会出 现 XSS 缺陷。XSS 让攻击者能够在受害者的浏览器中执行脚本,并劫持用户 会话、破坏网站或将用户重定向到恶意站点。

在表单提交或者 url 参数传递前,对需要的参数进行过滤; 2.过滤用户输入的 检查用户输入的内容中是否有非法内容。如<>(尖括号)、” (引号)、 ‘(单引号)、%(百分比符号)、;(分号)、()(括号)、&(& 符号)、+(加号)等。、严格控制输出

首先在web.xml中加入如下配置


    XssEscape
    cn.zjcom.common.xss.RequestXssFilter
    true


    XssEscape
    /*
    REQUEST

新增RequestXssFilter类

public class RequestXssFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(RequestXssFilter.class);

    /**
     * IP白名单
     */
    private static final String WHITE_LIST[] = {"192.168.10.50"
            , "127.0.0.1"
            , "192.168.1.10"
            , "localhost"
            , "pay.nh2v.cn"
            , "file.zgjb.cn"
            , "192.168.10.190"
    };

    FilterConfig filterConfig = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String host = request.getHeader("Host");
        if (!isEmpty(host)) {
            if (checkBlankList(host)) {
//                filterChain.doFilter(servletRequest, servletResponse);
                filterChain.doFilter(new XssHttpServletRequestWrapper(
                        (HttpServletRequest) servletRequest), servletResponse);
            } else {
                log.debug("[hostfilter deny access tips]->" + host);
                response.getWriter().print("request deny");
                response.flushBuffer();
            }
        } else {
            filterChain.doFilter(new XssHttpServletRequestWrapper(
                    (HttpServletRequest) servletRequest), servletResponse);
        }
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }

    /**
     * 校验当前host是否在白名单中
     *
     * @param host
     * @return
     */
    private boolean checkBlankList(String host) {
        for (String item : WHITE_LIST) {
            if (host.contains(item)) {
                return true;
            }
        }
        return false;
    }

    public boolean validateCsrfToken(HttpServletRequest req) {
        HttpSession s = req.getSession();
        String sToken = (String) s.getAttribute("csrftoken");
        if (sToken == null) {
            sToken = IdGenerator.getId32();
            s.setAttribute("csrftoken", sToken);
            return true;
        } else {
            // 从 HTTP 头中取得 csrftoken
            String xhrToken = req.getHeader("csrftoken");

            // 从请求参数中取得 csrftoken
            String pToken = req.getParameter("csrftoken");
            if (sToken != null && xhrToken != null && sToken.equals(xhrToken)) {
                return true;
            } else if (sToken != null && pToken != null && sToken.equals(pToken)) {
                return true;
            } else {
                return false;
            }
        }
    }

    public boolean isEmpty(Object str) {
        return str == null || "".equals(str);
    }
}

然后新增XssHttpServletRequestWrapper类

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    //白名单数组
    private static final String[] WHITE_LIST = {"content", "notice.content", "adviceNote"};
    // 定义script的正则表达式
    private static final String REGEX_SCRIPT = "<((?i)script)[^>]*?>[\\s\\S]*?<\/((?i)script)>";
    // 定义style的正则表达式
    private static final String REGEX_STYLE = "<((?i)style)[^>]*?>[\\s\\S]*?<\/((?i)style)>";
    // 定义HTML标签的正则表达式
    private static final String REGEX_HTML = "<[^>]+>";
    // 定义空格回车换行符
    private static final String REGEX_SPACE = "\\r|\n";
    //定义所有w标签
    private static final String REGEX_W = "<((?i)w)[^>]*?>[\\s\\S]*?<\/((?i)w)[^>]*?>";
    //定义SQL注入
    private static String reg = "(?i)(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
    // 窗口事件
    private static final String WINDOW_EVENT_REGEX = "onafterprint|onbeforeprint|onbeforeonload|onblur|onerror|onfocus|onhashchange|onload|onmessage|onoffline|ononline|onpagehide|onpageshow|onpopstate|onredo|onresize|onstorage|onundo|onunload";
    // 表单事件
    private static final String FORM_EVENT_REGEX = "onblur|onchange|oncontextmenu|onfocus|onformchange|onforminput|oninput|oninvalid|onreset|onselect|onsubmit";
    // 键盘事件
    private static final String KEYBOARD_EVENT_REGEX = "onkeydown|onkeypress|onkeyup";
    // 鼠标事件
    private static final String MOUSE_EVENT_REGEX = "onclick|ondblclick|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onscroll";
    // 多媒体事件
    private static final String MEDIA_EVENT_REGEX = "onabort|oncanplay|oncanplaythrough|ondurationchange|onemptied|onended|onerror|onloadeddata|onloadedmetadata|onloadstart|onpause|onplay|onplaying|onprogress|onratechange|onreadystatechange|onreadystatechange|onseeked|onseeking|onstalled|onsuspend|ontimeupdate|onvolumechange|onwaiting";
    // 其他事件
    private static final String OTHER_EVENT_REGEX = "onshow|ontoggle";
    // 定义URL中特殊字符
    private static final String SPECIAL_CHARACTERS = "\\*|\\\\|\\'|\\||\\&|\\$|\\#|\\@|\\!|<|>|\\+|\\=";

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @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++) {
            //白名单放行的只有HTML标签,SQL标签还是要验证
            if (isWhitelist(parameter)) {
                encodedValues[i] = values[i];
            } else {
                if (!sqlValidate(values[i])) {
                    return null;
                }
                if (!specialCharactersValidate(values[i])) {
                    return null;
                }
                encodedValues[i] = removeHtml(values[i]);
            }
        }

        return encodedValues;

    }

    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        if (value == null) {
            return null;
        }
        //白名单放行的只有HTML标签,SQL标签还是要验证
        if (isWhitelist(parameter)) {
            return value;
        }
        value = removeHtml(value);
        if (!sqlValidate(value)) {
            return null;
        }
        if (!specialCharactersValidate(value)) {
            return null;
        }
        return value;
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null) {
            return null;
        }

        if (isWhitelist(name)) {
            return value;
        }
        return removeHtml(value);
    }


    //\b  表示 限定单词边界  比如  select 不通过   1select则是可以的
    private static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);

    /**
     * SQL注入过滤器
     *
     * @param str
     * @return
     */
    private static boolean sqlValidate(String str) {
        if (sqlPattern.matcher(str).find()) {
            System.out.println("未能通过过滤器:str=" + str);
            return false;
        }
        return true;
    }

    /**
     * 是否白名单,白名单的放行
     *
     * @param paramName
     * @return
     */
    private static boolean isWhitelist(String paramName) {
        String lowerParam = paramName.toLowerCase();
        String name = Arrays.stream(WHITE_LIST).filter(y -> y.toLowerCase().equals(lowerParam)).findAny().orElse(null);
        return name != null;
    }

    /**
     * 移除HTML标签
     *
     * @param htmlStr
     * @return
     */
    private static String removeHtml(String htmlStr) {

        Pattern p_script = Pattern.compile(REGEX_SCRIPT, Pattern.CASE_INSENSITIVE);
        Matcher m_script = p_script.matcher(htmlStr);
        htmlStr = m_script.replaceAll(""); // 过滤script标签

        Pattern p_style = Pattern.compile(REGEX_STYLE, Pattern.CASE_INSENSITIVE);
        Matcher m_style = p_style.matcher(htmlStr);
        htmlStr = m_style.replaceAll(""); // 过滤style标签

        Pattern p_html = Pattern.compile(REGEX_HTML, Pattern.CASE_INSENSITIVE);
        Matcher m_html = p_html.matcher(htmlStr);
        htmlStr = m_html.replaceAll(""); // 过滤html标签

        Pattern p_w = Pattern.compile(REGEX_W, Pattern.CASE_INSENSITIVE);
        Matcher m_w = p_w.matcher(htmlStr);
        htmlStr = m_w.replaceAll(""); // 过滤script标签

        Pattern p_space = Pattern.compile(REGEX_SPACE, Pattern.CASE_INSENSITIVE);
        Matcher m_space = p_space.matcher(htmlStr);
        htmlStr = m_space.replaceAll(""); // 过滤空格回车标签

        // 过滤HTML窗口事件
        Pattern p_window_event = Pattern.compile(WINDOW_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_window_event = p_window_event.matcher(htmlStr);
        htmlStr = m_window_event.replaceAll("");
        // 过滤HTML表单事件
        Pattern p_form_event = Pattern.compile(FORM_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_form_event = p_form_event.matcher(htmlStr);
        htmlStr = m_form_event.replaceAll("");
        // 过滤HTML键盘事件
        Pattern p_keyboard_event = Pattern.compile(KEYBOARD_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_keyboard_event = p_keyboard_event.matcher(htmlStr);
        htmlStr = m_keyboard_event.replaceAll("");
        // 过滤HTML鼠标事件
        Pattern p_mouse_event = Pattern.compile(MOUSE_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_mouse_event = p_mouse_event.matcher(htmlStr);
        htmlStr = m_mouse_event.replaceAll("");
        // 过滤HTML多媒体事件
        Pattern p_media_event = Pattern.compile(MEDIA_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_media_event = p_media_event.matcher(htmlStr);
        htmlStr = m_media_event.replaceAll("");
        // 过滤HTML其它事件
        Pattern p_other_event = Pattern.compile(OTHER_EVENT_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher m_other_event = p_other_event.matcher(htmlStr);
        htmlStr = m_other_event.replaceAll("");

//        Pattern p_fh = Pattern.compile(REGEX_FH, Pattern.CASE_INSENSITIVE);
//        Matcher m_fh = p_fh.matcher(htmlStr);
//        htmlStr = m_fh.replaceAll(""); // 过滤特殊符号

//        htmlStr = htmlStr.replaceAll(" ", ""); //过滤
        return htmlStr.trim(); // 返回文本字符串
//        return htmlStr; // 返回文本字符串
    }

    /**
     * 移除特殊字符
     *
     * @param value
     * @return
     */
    private static Boolean specialCharactersValidate(String value) {
        // 过滤特殊符号
        Pattern pattern = Pattern.compile(SPECIAL_CHARACTERS, Pattern.CASE_INSENSITIVE);
        if (pattern.matcher(value).find()) {
            System.out.println("特殊字符未能通过过滤器:str=" + value);
            return false;
        }
        return true;
    }
}
在博客中查看:Java利用拦截器处理XSS漏洞 - ZJBLOG

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/792522.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存