JavaWeb应⽤修复存储型XSS漏洞
⼀、问题背景
跨站脚本攻击的英⽂全称是Cross Site Script,为了和样式表区分,缩写为XSS。发⽣的原因是⽹站将⽤户输⼊的内容输出到页⾯上,在这个过程中可能有恶意代码被浏览器执⾏。跨站脚本攻击,它指的是恶意攻击者往Web页⾯⾥插⼊恶意html代码,当⽤户浏览该页之时,嵌⼊其中Web⾥⾯的html代码会被执⾏,从⽽达到恶意⽤户的特殊⽬的。已知的跨站脚本攻击漏洞有三种:1)存储式;2)反射式;3)基于DOM。
1、存储型跨站脚本攻击涉及的功能点:⽤户输⼊的⽂本信息保存到数据库中,并能够在页⾯展⽰的功能点,例如⽤户留⾔、发送站内消息、个⼈信息修改等功能点。
2、反射型跨站脚本攻击涉及的功能点:URL参数需要在页⾯显⽰的功能点都可能存在反射型跨站脚本攻击,例如站内搜索、查询功能点。
3、基于DOM跨站脚本攻击涉及的功能点:涉及DOM对象的页⾯程序,包括(不限这些)。
漏洞危害
常见的反射型跨站脚本攻击步骤如下:
1)攻击者创建并测试恶意URL;
2)攻击者确信受害者在浏览器中加载了恶意URL;
3)攻击者采⽤反射型跨站脚本攻击⽅式安装键盘记录器、窃取受害者的cookie 、窃取剪贴板内容、改变⽹页内容(例如下载链接)。
存储型跨站脚本攻击最为常见的场景是将跨站脚本写⼊⽂本输⼊域中,如留⾔板、博客或新闻发布系统的评论框。当⽤户浏览留⾔和评论时,浏览器执⾏跨站脚本代码。
例如,在某个系统的⽂本输⼊框中输⼊如下的⽰例攻击代码⽚段<script>alert(2)</script>,如果弹出如下的弹窗,则说明对应系统存在被XSS攻击的风险:
image.png
加固建议:
总体修复⽅式:验证所有输⼊数据,有效检测攻击;对所有输出数据进⾏适当的编码,以防⽌任何已成功注⼊的脚本在浏览器端运⾏。具体如下:
1)输⼊验证:某个数据被接受为可被显⽰或存储之前,使⽤标准输⼊验证机制,验证所有输⼊数据的长度、类型、语法以及业务规则。
2)输出编码:数据输出前,确保⽤户提交的数据已被正确进⾏entity编码,建议对所有字符进⾏编码⽽不仅局限于某个⼦集。
3)明确指定输出的编码⽅式:不要允许攻击者为你的⽤户选择编码⽅式(如ISO 8859-1或 UTF 8)。
4)注意⿊名单验证⽅式的局限性:仅仅查或替换⼀些字符(如"<" ">"或类似"script"的关键字),很容易被XSS变种攻击绕过验证机制。
5)警惕规范化错误:验证输⼊之前,必须进⾏解码及规范化以符合应⽤程序当前的内部表⽰⽅法。请确定应⽤程序对同⼀输⼊不做两次解码。对客户端提交的数据进⾏过滤,⼀般建议过滤掉双引号(”)、尖括号(<、>)等特殊字符,或者对客户端提交的数据中包含的特殊字符进⾏实体转换,⽐如将双引号(”)转换成其实体形式",<;对应的实体形式是<,<;对应的实体形式是>以下为需过滤的
常见字符:
6)对参数中的特殊字符进⾏转义或者编码,如:“’、”、<、>、(、=、.”等特殊字符。
⼆、修复⽅案
*/
@Override
public String getParameter(String parameter) {
String value = Parameter(parameter);
return stripXSS(parameter, value);
}
/**
* 处理query String参数
*/
@Override
public String[] getParameterValues(String parameter) {
String path = ServletPath();
String[] values = ParameterValues(parameter);
springmvc的注解有哪些// 排除没有请求参数和⽆需校验的路径
if (values == null || enableNoCheckURL(NO_CHECK_URL_PATTERN_LIST, path)) { return values;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = stripXSS(parameter, values[i]);
}
return encodedValues;
}
@Override
public ServletInputStream getInputStream() throws IOException {
body = Request());
ServletInputStream inputStream = null;
if (StringUtils.isNotEmpty(body)) {
Map<String, Object> paramMap = JSON.parseObject(body);
for (Map.Entry<String, Object> entry : Set()) {
paramMap.put(StringEscapeUtils.Key()),
StringEscapeUtils.Value().toString()));
}
body = JSONString(paramMap);
inputStream = new PostServletInputStream(body);
}
return inputStream;
}
@Override
public BufferedReader getReader() throws IOException {
body = Request());
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding = "UTF-8";
}
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 过滤参数
*
* @param value 参数值
* @param parameter 参数name名
* @return
*/
private String stripXSS(String parameter, String value) {
String newValue = value;
if (newValue != null && enableNoCheckParameter(parameter)) {
if (JSONUtils.isJSONValid(newValue)) {
// HtmlUtils.htmlEscape(value);
// StringEscapeUtils.unescapeJson(value);
newValue = SecurityUtil.escapeJsonWithoutAmpersand(value);
} else {
// StringEscapeUtils.escapeHtml4(value);
// HtmlUtils.htmlEscape(value);//spring的HtmlUtils进⾏转义
newValue = SecurityUtil.escapeHtmlWithoutAmpersand(value);
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论