生活不易、且行且珍惜。网站首页 程序人生
Java利用拦截器处理XSS漏洞
发布时间:2022-04-29 22:17编辑:zj 阅读:文章分类:
Java互动QQ群:170915747
<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; } }
ok 解决~
#去评论一下
标签:#漏洞
版权声明:本博客的所有原创内容皆为作品作者所有
转载请注明:来自ZJBLOG 链接:www.zjhuiwan.cn


「万物皆有时,比如你我相遇」
感谢大佬打赏【请选择支付宝或微信,再选择金额】
使用微信扫描二维码完成支付
