攻击通过在授权用户访问的页面中包含链接或者脚本的方式工作。例
如:一个网站用户Bob可能正在浏览聊天论坛,而同时另一个用户Alice也在此论坛中,并且后者刚刚发布了一个具有Bob银行链接的图片消息。设想一下,Alice编写了一个在Bob的银行站点上进行取款的form提交的链接,并将此链接作为图片src。如果Bob的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当Bob的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经Bob同意的情况下便授权了这次事务。
CSRF是一种依赖web浏览器的、被混淆过的代理人攻击(deputy attack)。在上面银行示例中的代理人是Bob的web浏览器,它被混淆后误将Bob的授权直接交给了Alice使用。
通过实现Filter过滤器对每一次请求进行验证,验证方式是:验证请求的Referer是否有效
package com.skysz.framework.filter.csrf;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import com.skysz.framework.logger.SkyszLogger;
import com.skysz.framework.logger.SkyszLoggerF;
import com.skysz.framework.utils.StringUtils;
public class CSRFFilter implements Filter {
private static SkyszLogger log = SkyszLoggerF.getLog(CSRFFilter.class);
private static String IPAUTHFILTER = "";// 请求IP地址白名单
private static String CSRFFILTEREPARM = "";// 请求URL白名单
@Override
public void init(FilterConfig filterConfig) throws ServletException {
IPAUTHFILTER = filterConfig.getInitParameter("ipAuthFilter");
CSRFFILTEREPARM = filterConfig.getInitParameter("csrfFiltereParm");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// 从 HTTP 头中取得 Referer 值
String referer = req.getHeader("Referer");
String reqUrl = req.getRequestURL().toString();
String whiteIpAll = IPAUTHFILTER;
String[] whiteParams = CSRFFILTEREPARM.split(","); // 可以直接放行的路径,不用校验referer
if (StringUtils.isNullOrBlank(whiteIpAll)) {
log.error("CSRFFilter:The header is null ...");
PrintWriter writer = response.getWriter();
writer.println("The header is null");
writer.close();
return;
}
String[] whiteIPs = whiteIpAll.split(","); //
boolean isgo = false; // 是否可以放行的标志
// 如果referer为null的处理(ie windows.open() referer是为null的)
if (StringUtils.isNullOrBlank(referer)) {
// 匹配是否是合法请求(刚进入登录页面 referer为null)
for (String whiteIP : whiteIPs) {
if (reqUrl.equals(whiteIP)) {
log.info("referer为null,请求路径:" + reqUrl + "和配置的" + whiteIP + "相等,此请求为合法请求,登录页面放行!");
isgo = true;
break;
}
}
// 如果isgo已经为true则放行,后面的验证不在执行
if (!isgo) {
// 如果referer为null则用请求的url和可以放行的路径比对
for (String whiteParam : whiteParams) {
if (reqUrl.contains(whiteParam)) {
log.info("referer为null,请求路径:" + reqUrl + "包含" + whiteParam + ",此请求为合法请求,放行!");
isgo = true;
break;
}
}
}
} else { // 如果referer不为null的处理
for (int i = 0; i < whiteIPs.length; i++) {
if (referer.trim().contains(whiteIPs[i])) {
// log.info("referer的值为:" + referer + "包含" + whiteIPs[i] + ",此请求为合法请求,放行!");
isgo = true;
break;
}
}
}
if (!isgo) {
log.error("referer的值为:" + referer + ",请求路径为:" + reqUrl + ",IP白名单:" + IPAUTHFILTER + ",参数url白名单:" + CSRFFILTEREPARM + ",不合法请求,拦截!");
PrintWriter writer = response.getWriter();
writer.println("The request you sent was exceptionally malicious " + referer + " contains :" + isgo + "(CSRF)");
writer.close();
return;
}
chain.doFilter(request, response);
}
public String generate() {
return UUID.randomUUID().toString();
}
@Override
public void destroy() {
}
}
//在web.xml加上这个过滤器
<filter>
<filter-name>CSRFFilter</filter-name>
<filter-class>com.text.framework.filter.csrf.CSRFFilter</filter-class>
<init-param>
<param-name>ipAuthFilter</param-name>
<param-value>http://localhost:8015/</param-value>
</init-param>
<init-param>
<param-name>csrfFiltereParm</param-name>
<param-value>index.html,index.jsp,app/authAction/loadAuthTopMenus.html,/app/hx/dzhd/accountReceipt_showReceipt.jsp,/app/hx/authCsrf/,/app/payFileAction/uploadAccsTemp.html/,/views/file/,/app/attachmentAction/uploadAccs.html</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CSRFFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>