漏洞原理:
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意的特殊目的。
业务影响:
通过XSS攻击可以攻击到网站管理员后台和平行的用户
安全关注点:
跨站可以导致用户的认证信息被盗,被钓鱼,被挂马等
解决方案:
对输出变量中的危险符号< >";'( ) 等进行转义处理词转义处理或者过滤。
工具测试方案:
展开能看到更多详情,右侧为漏洞详情和payload,可用来做手工验证
手工测试方案:
上面说的是反射型XSS漏洞,还有一种漏洞是存储型XSS漏洞,相较反射型XSS漏洞危害更大,但是此类漏洞很难用工具自动检测,更多的是手工测试。反射XSS需要受害者去点击链接,才能够触发,而存储型XSS,往往更加稳定的存在,任何人只要访问了存在Payload的页面,即可触发。
2写一个filter
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意的特殊目的。
业务影响:
通过XSS攻击可以攻击到网站管理员后台和平行的用户
安全关注点:
跨站可以导致用户的认证信息被盗,被钓鱼,被挂马等
解决方案:
对输出变量中的危险符号< >";'( ) 等进行转义处理词转义处理或者过滤。
工具测试方案:
打开WVS,点击左上角的New Scan
在弹出窗口中输入要扫描的网址
点击 Next,出现窗口中选择XSS,测试模版
扫描结果如下图,红色感叹号即为扫到的XSS漏洞
展开能看到更多详情,右侧为漏洞详情和payload,可用来做手工验证
还是拿上面的例子来说,首先对我们的输入用burpsuite进行抓包,如下图
可以清楚的看到http请求的内容,在空白处点击右键,选择Send to Repeater
然后点开repeater标签
点击Go,即可看到服务器返回的数据
在右侧搜索我们输入的字符串,可以看到右侧有输出
我们把输入的部分改成 <script>alert(1)</script>,点击Go看回显,payload原封不动的输出了,这里有一个需要注意的,服务器返回的数据中,下图中标出来的头部必须是html才可以触发,否则就算服务器返回了输入的payload,浏览器也不会执行,下图这个状态就说明存在XSS漏洞
上面说的是反射型XSS漏洞,还有一种漏洞是存储型XSS漏洞,相较反射型XSS漏洞危害更大,但是此类漏洞很难用工具自动检测,更多的是手工测试。反射XSS需要受害者去点击链接,才能够触发,而存储型XSS,往往更加稳定的存在,任何人只要访问了存在Payload的页面,即可触发。
案例:某论坛,有人发了一篇帖子,所有的人都能看帖子,注册用户可以回帖,回帖功能存在存储型XSS,这时有个用户发了一个恶意的回复内容,服务端将内容存入数据库,有人访问页面的时候就在页面上显示回复内容,但这个内容是用户输入的恶意内容,服务端如果未作过滤就显示在页面上,那么谁访问该页面,谁就中招(触发攻击)。
然后我们看具体的代码示例
1在web.xml配置
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>com.jd.noah.cms.web.util.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XssFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2写一个filter
package com.jd.noah.cms.web.util;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Set;
/**
* xss攻击的预防过滤器
* Created by jiangkunkun on 2016/12/26
*/
public class XssFilter implements Filter {
FilterConfig filterConfig = null;
/**
* 需要匹配替换的正则表达式
*/
private String regEx;
/**
* 过滤器排除url集合
*/
private Set<String> excluded;
/**
* 过滤器初始化方法
* @param filterConfig
* @throws ServletException
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
if (filterConfig.getInitParameter("regEx") != null) {
regEx = filterConfig.getInitParameter("regEx");
}
if (filterConfig.getInitParameter("excluded") != null) {
String excludedStr = filterConfig.getInitParameter("excluded");
if (excludedStr.contains(",")) {
String[] arr = excludedStr.split(",");
for (String s : arr) {
excluded.add(s.trim());
}
} else {
excluded.add(excludedStr);
}
}
}
//
public void destroy() {
this.filterConfig = null;
}
//
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest inRequest = (HttpServletRequest) request;
String uri = inRequest.getRequestURI();
if (simpleMatch(excluded, uri)) {
chain.doFilter(request, response);
return;
}
chain.doFilter(new XssHttpServletRequestWrapper(
inRequest,this.regEx), response);
}
private static boolean simpleMatch(Set<String> patterns, String str) {
if (patterns == null || patterns.isEmpty() || str == null) {
return false;
}
for (String pattern : patterns) {
if (simpleMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* URL通配符匹配
* @param pattern
* @param str
* @return
*/
private static boolean simpleMatch(String pattern, String str) {
if (pattern == null || str == null) {
return false;
}
int firstIndex = pattern.indexOf('*');
if (firstIndex == -1) {
return pattern.equals(str);
}
if (firstIndex == 0) {
if (pattern.length() == 1) {
return true;
}
int nextIndex = pattern.indexOf('*', firstIndex + 1);
if (nextIndex == -1) {
return str.endsWith(pattern.substring(1));
}
String part = pattern.substring(1, nextIndex);
int partIndex = str.indexOf(part);
while (partIndex != -1) {
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
return true;
}
partIndex = str.indexOf(part, partIndex + 1);
}
return false;
}
return (str.length() >= firstIndex &&
pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) &&
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
}
}
3HttpServletRequestWrapper类
package com.jd.noah.cms.web.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 用户请求包装类
* Created by jiangkunkun on 2016/12/26
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* 需要匹配替换的正则表达式
*/
private String regEx;
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest,String regEx) {
super(servletRequest);
this.regEx = regEx;
}
@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++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
//
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
/**
* 清除替换XSS代码
* @param value
* @return
*/
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", "").trim();
/* String regEx="[`~!@#$%^&*()+=|{}':;',//[//].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?\"]";
if(this.regEx != null){
regEx = this.regEx;
}
Pattern p = Pattern.compile(regEx);
Matcher dataMatcher = p.matcher(value);
value = dataMatcher.replaceAll("").trim() ;*/
return value;
}
}