Ywc's blog

CSRF漏洞总结

Word count: 1.2kReading time: 4 min
2020/07/28

漏洞原理

CSRF(Cross-site request forgery),中文名称:跨站请求伪造。

CSRF漏洞是因为web应用程序在用户进行敏感操作时,如修改账号密码、添加账号、转账等,没有校验表单token或者http请求头中的referer值,从而导致恶意攻击者利用普通用户的身份(cookie)完成攻击行为

由于目标网站无token或referer限制,攻击者可以利用用户的身份,执行请求

跨站请求伪造,利用了网站允许攻击者预测特定操作所有细节这一特点。由于浏览器自动发送会话cookie等认证凭证,导致攻击者可以创建恶意的web页面来产生伪造请求。这些伪造的请求很难和合法的请求区分开

例如:

银行网站A,它以GET请求来完成银行转账的操作,如:

1
http://www.mybank.com/Transfer.php?toBankId=11&money=1000

危险网站B,它里面有一段HTML的代码如下:

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

登陆银行网站A后,在同一个浏览器去访问B网站的一个上面的请求,这个时候会发现你的账户会少了1000块。

漏洞危害

攻击者可以让受害者用户修改任何允许修改的数据,执行任何用户允许的操作,例如修改密码,登录注销等

漏洞测试

1.GET类型的CSRF的检测

如果有token等验证参数,先去掉参数尝试能否正常请求。如果可以,即存在CSRF漏洞

2.POST类型的CSRF的检测

如果有token等验证参数,先去掉参数尝试能否正常请求。如果可以,再去掉referer参数的内容,如果仍然可以,说明存在CSRF漏洞,可以利用构造外部form表单的形式,实现攻击。如果直接去掉referer参数请求失败,这种还可以继续验证对referer的判断是否严格,是否可以绕过

漏洞修复

添加验证码:在一些特殊请求页面增加验证码,验证码强制用户必须与应用进行交互,才能完成最终请求

检测refer:检测refer值,来判断请求来源是否合法。

Token:在每个请求中设置Token是一种流行的方式来防御CSRF。CSRF攻击的原理:攻击者可以猜测到用户请求,现在在每个请求中加一个随机的Toekn值。

Token要足够随机————只有这样才算不可预测

Token是一次性的,即每次请求成功后要更新Token————这样可以增加攻击难度,增加预测难度

Token要注意保密性————敏感操作使用post,防止Token出现在URL中

代码示例

Token使用

说明:在重要操作的表单中增加会话生成的Token字段,一次一用,提交后在服务端校验该字段。

Java示例:用户登录后生成token:

1
2
3
4
5
6
7
8
9
10
//获取用户的输入验证业务逻辑
String user = request.getParameter("user");
String password = request.getParameter("password");
String capature = request.getParameter("kaptcha");
if(validate_user(user, password, capature)) {
sessLogin = request.getSession(true);
sessLogin.setAttribute("LOGIN", true);
//生成随机字符的 token 并存入到用户会话中
sessLogin.setAttribute("csrf_token",getRandomString(20));
}

页面(模板)渲染时输出token

输出到链接:

1
2
3
4
5
6
7
8
<a href=logout.jsp?token=<%sessLogin.getAttribute("token")%>">logout</a>
输出到form表单:
<form method="POST">
发信息:
<input name="message" type="text">
<input type="hidden" name="token" value=<%=sessLogin.getAttribute("token")%/>
<input type=submit value="post">
</form>

服务端逻辑检查中验证token是否正确:

1
2
3
if (sessLogin.getAttribute("token").equals(request.getParameter("token"))) {
//处理应用逻辑
}

二次验证

说明:在关键表单提交时,要求用户进行二次身份验证,如密码、图片验证码、短信验证码等。

Referer 验证

说明:检验用户请求中Referer字段是否存在跨域提交的情况。

Java示例:检查请求连接的referer是否合法

1
2
3
4
5
6
7
8
9
String expectedRefererStartsWith = “https://xxx.test.com”
// 从 HTTP 头中取得 Referer 值
String referer=request.getHeader("referer");
// 判断 Referer 是否以 https://xxx.test.com 开头
if((referer!=null) &&(referer.trim().startsWith(expectedRefererStartsWith))){
chain.doFilter(request, response);
}else{
request.getRequestDispatcher(“error.jsp”).forward(request,response);
}

Reference

https://sobug.com/article/detail/10
https://xz.aliyun.com/t/7450#toc-3
https://blog.csdn.net/weixin_45728976/article/details/104506544

CATALOG
  1. 1. 漏洞原理
  2. 2. 漏洞危害
  3. 3. 漏洞测试
  4. 4. 漏洞修复
    1. 4.1. 代码示例
  5. 5. Reference