Java利用拦截器处理XSS漏洞

26 篇文章 1 订阅

Java利用拦截器处理XSS漏洞

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

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

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

<filter>
    <filter-name>XssEscape</filter-name>
    <filter-class>cn.zjcom.common.xss.RequestXssFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>XssEscape</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

新增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

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java过滤器处理XSS攻击的示例代码: ```java import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.*; public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { MyHttpServletRequestWrapper requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) servletRequest); HttpServletResponse response = (HttpServletResponse) servletResponse; filterChain.doFilter(requestWrapper, response); } @Override public void destroy() { } private class MyHttpServletRequestWrapper extends HttpServletRequestWrapper { public MyHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String value = super.getParameter(name); if (value != null) { value = cleanXSS(value); } return value; } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values != null) { for (int i = 0; i < values.length; i++) { values[i] = cleanXSS(values[i]); } } return values; } @Override public Enumeration<String> getParameterNames() { List<String> names = Collections.list(super.getParameterNames()); return Collections.enumeration(names); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> paramMap = super.getParameterMap(); Map<String, String[]> newParamMap = new HashMap<>(); for (String key : paramMap.keySet()) { String[] values = paramMap.get(key); for (int i = 0; i < values.length; i++) { values[i] = cleanXSS(values[i]); } newParamMap.put(key, values); } return newParamMap; } private String cleanXSS(String value) { value = value.replaceAll("<", "<").replaceAll(">", ">"); value = value.replaceAll("\\(", "(").replaceAll("\\)", ")"); value = value.replaceAll("'", "'"); value = value.replaceAll("eval\\((.*)\\)", ""); value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); value = value.replaceAll("script", ""); return value; } } } ``` 该过滤器通过继承HttpServletRequestWrapper类,重写其中的getParameter()、getParameterValues()、getParameterNames()和getParameterMap()方法,对请求参数进行过滤,防止XSS攻击。其中,cleanXSS()方法用于过滤请求参数中的特殊字符和脚本代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值