释意:
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
原理:
image从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
登录受信任网站A,并在本地生成Cookie。
在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
如何防御CSRF
1.提交验证码
在表单中增加一个随机的数字或字母验证码,通过强制用户和应用进行交互,来有效地遏制CSRF攻击。
2.Referer Check(referer:标志请求来源)
检查如果是非正常页面过来的请求,则极有可能是CSRF攻击。
3.token验证
在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有
token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
token需要足够随机
敏感的操作应该使用POST,而不是GET,以form表单的形式提交,可以避免token泄露。
4.在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
eip6.0处理csrf方式
csrf过滤器:
referer检查如果是非正常页面过来的请求,则极有可能是CSRF攻击。
自定义请求头“supporter”,根据电话、邮箱、日期、特殊字符、base64前台加密,后台过滤器解析。
package com.supporter.prj.eip.webapp.filter;
import com.supporter.prj.eip_service.exception.BaseRuntimeException;
import com.supporter.util.CommonUtil;
import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 org.apache.commons.lang3.StringUtils;
public class CsrfFilter
implements Filter
{
private static final String KEY_BEGIN = "begin";
private static final String KEY_END = "end";
private static final String KEY_EQUALS = "equals";
private List<String> specialCharacters = new ArrayList();
private static List<Map<String, String>> excludes;
public void init(FilterConfig filterConfig)
throws ServletException
{
List chars = Arrays.asList(new String[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" });
this.specialCharacters.addAll(chars);
initExcludeConfig(filterConfig);
}
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)srequest;
if (isExcludeUrl(request)) {
chain.doFilter(request, sresponse);
} else {
String supporter = request.getHeader("supporter");
if (supporter != null) {
boolean isPassed = checkKeyPassed(supporter);
if (!isPassed) {
throw new BaseRuntimeException("503", "非法操作!");
}
chain.doFilter(request, sresponse);
}
else {
String referer = request.getHeader("referer");
if (referer == null) {
System.out.println("检验非法操作:---" + request.getRequestURL());
throw new BaseRuntimeException("503", "非法操作!");
}
chain.doFilter(request, sresponse);
}
}
}
public void destroy()
{
}
private boolean checkKeyPassed(String supporter)
throws IOException
{
String orignSupporter = new String(CommonUtil.decodeBASE64(supporter));
String phone = orignSupporter.substring(0, 12);
String email = orignSupporter.substring(12, 33);
String day = orignSupporter.substring(33, 43);
String rdm = orignSupporter.substring(51, 56);
String specialChar = orignSupporter.substring(57);
if ((StringUtils.isBlank(phone)) || (StringUtils.isBlank(email)) || (StringUtils.isBlank(day)) ||
(StringUtils.isBlank(rdm)) || (StringUtils.isBlank(specialChar))) {
return false;
}
if (!"010-62415868".equals(phone)) {
return false;
}
if (!"supporter@dhcc.com.cn".equals(email)) {
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String today = sdf.format(new Date());
if (!today.equals(day)) {
return false;
}
if (!CommonUtil.isNumber(rdm)) {
return false;
}
return this.specialCharacters.contains(specialChar);
}
private boolean isExcludeUrl(HttpServletRequest request)
throws IOException, ServletException
{
String contextPath = request.getContextPath();
int index = request.getRequestURI().indexOf(contextPath);
String uri = request.getRequestURI().substring(index + contextPath.length());
if (excludes != null) {
for (Map data : excludes) {
String begin = (String)data.get("begin");
String end = (String)data.get("end");
String equals = (String)data.get("equals");
if (((begin == null) || (uri.startsWith(begin))) &&
((end == null) || (uri.endsWith(end))) && (
(equals == null) || (uri.equals(equals))))
{
return true;
}
}
}
return false;
}
private void initExcludeConfig(FilterConfig filterConfig)
{
String exclude = filterConfig.getInitParameter("excludedCheckURLList");
if ((exclude != null) && (exclude.length() > 0)) {
String[] excludesVal = exclude.replaceAll("\n", "").replaceAll("\t", "").split(";");
excludes = new ArrayList();
for (String val : excludesVal) {
val = val.trim();
Map data = new HashMap();
int i = val.indexOf("*");
if (i > -1) {
String begin = val.substring(0, i);
if ((begin != null) && (begin.length() > 0)) {
data.put("begin", begin.trim());
}
String end = val.substring(i + 1);
if ((end != null) && (end.length() > 0))
data.put("end", end.trim());
}
else {
data.put("equals", val);
}
excludes.add(data);
}
}
}
}
网友评论