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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)