前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java利用拦截器处理XSS漏洞

Java利用拦截器处理XSS漏洞

作者头像
sunonzj
发布2022-06-21 09:21:31
8710
发布2022-06-21 09:21:31
举报
文章被收录于专栏:zjblogzjblog

Java利用拦截器处理XSS漏洞

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

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

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

代码语言:javascript
复制
<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类

代码语言:javascript
复制
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类

代码语言:javascript
复制
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 解决~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档