欢迎来到.NET绿叶网!

跨站点请求伪造(CSRF)

2018-01-11 CSRF 跨站点请求伪造

CSRF(Cross-site request forgery跨站请求伪造,也被称成为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

a651c998da0f4a83845d2394e6776033.jpg

说的白话一点就是,别的站点伪造你的请求。下面有个经典的实例,了解一下跨站点请求伪造到底是怎么是实现的:

受害者:Paul

黑客:Jack

银行:bank

Paul在银行有一笔存款,可以通过请求http://bank.com/withdraw?account=bob&amount=1000000&for=Linda把钱转到Linda下。通常情况下,该请求到达网站后,服务器会验证请求是否来自一个合法的session,并且该session的用户Paul已登录。Jack在该银行也有账户,于是他伪造了一个地址http://bank.com/withdraw?account=Paul&amount=1000000&for=Jack,但是如果直接访问,服务器肯定会识别出当前登录用户是Jack而不是Paul,不能接受请求。于是通过CSRF攻击方式,将此链接伪造在广告下,诱使Paul自己点这个链接,那么请求就会携带Paul浏览起的cookie一起发送到银行,而Paul同时又登录了银行或者刚刚登录不久session还没有过期,那服务器发现cookie中有Paul的登录信息,就接收了响应,攻击就成功了

本文以.NET为例,主要阐述服务端如何防御跨站点请求伪造(CSRF)

1、验证Referer

if (Request.UrlReferrer == null)
{
    throw new Exception("请求来源异常");
}
else
{
    if (Request.UrlReferrer.Host != Request.Url.Host)
    {
        throw new Exception("请求来源异常");
    }
}

代码中检查了请求来源与当前Host是否相同,如果UrlReferrer为空或者与当前Host不同则抛出异常。用这样的方法防止跨站点请求伪造比较简单粗暴,但是UrlReferrer是可以伪造的。

2、在请求参数中添加token验证

例如在一个表单提交页面,可以先生成一个CsrfToken,CsrfToken可以保存在Session中,表单提交时带上这个Token值。接收表单时,检查提交过来的Token与Session中的Token是否一致,如果一致在对表单进行处理。这样可以防止伪造的请求,示例代码如下:

if (Session["CsrfToken"] == null)
{
    throw new Exception("请求异常,请重试");
}
string csrfToken = Session["CsrfToken"].ToString();
Session["CsrfToken"] = null;
if (Request["CsrfToken "]!= csrfToken)
{
    throw new Exception("请求异常,请重试");
}

这样做还能防止重复提交。

3、HTTP头中自定义属性并验证

这个方法和上面那个类似,也是设置token,只是把token设置为HTTP头中的自定义属性。

通过XMLHttpRequest可以一次性给所有该类请求的HTTP头加上token 属性,但是XMLHttpRequest请求通常用于Ajax方法对局部页面的异步刷新,比较有局限性;而且通过XMLHttpRequest请求的地址不会被记录到浏览器的地址栏,一方面不会通过Referer泄露token,另一方面会导致前进,后退,刷新,收藏等操作失效,所以还是慎用。

个人认为通过Referer和Token方案结合起来使用,能够比较好的防止跨站点请求伪造(CSRF)