CSRF的详细介绍与token的分析

CSRF的攻击与防御

CSRF是Web应用程序的一种常见漏洞,其攻击特性是危害性大但非常隐蔽,尤其是在大量Web 2.0技术的应用背景下,攻击者完全可以在用户毫无察觉的情况下发起CSRF攻击。本文将对其基本特性、攻击原理、攻击分类、检测方法及防范手段做一个系统的阐述,并列举攻击实例。

1、CSRF漏洞简介

CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在未授权的情况下执行在权限保护之下的操作,具有很大的危害性。具体来讲,可以这样理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。

2、CSRF攻击原理及实例

CSRF攻击原理

CSRF攻击原理比较简单,如图1所示。其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。

图1 CSRF攻击原理

1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

CSRF攻击分类

CSRF漏洞一般分为站外和站内两种类型。

CSRF站外类型的漏洞本质上就是传统意义上的外部提交数据问题。通常程序员会考虑给一些留言或者评论的表单加上水印以防止SPAM问题(这里,SPAM可以简单的理解为垃圾留言、垃圾评论,或者是带有站外链接的恶意回复),但是有时为了提高用户的体验性,可能没有对一些操作做任何限制,所以攻击者可以事先预测并设置请求的参数,在站外的Web页面里编写脚本伪造文件请求,或者和自动提交的表单一起使用来实现GET、POST请求,当用户在会话状态下点击链接访问站外Web页面,客户端就被强迫发起请求。

CSRF站内类型的漏洞在一定程度上是由于程序员滥用$_REQUEST类变量造成的。在一些敏感的操作中(如修改密码、添加用户等),本来要求用户从表单提交发起POST请求传递参数给程序,但是由于使用了$_REQUEST等变量,程序除支持接收POST请求传递的参数外也支持接收GET请求传递的参数,这样就会为攻击者使用CSRF攻击创造条件。一般攻击者只要把预测的请求参数放在站内一个贴子或者留言的图片链接里,受害者浏览了这样的页面就会被强迫发起这些请求。

CSRF攻击实例

下面介绍CSRF攻击具体实施过程。

Axous是一款网上商店应用软件。Axous在实现上存在一个CSRF漏洞,远程攻击者可以通过构造特制的网页,诱使该软件管理员访问,成功利用此漏洞的攻击者可以添加系统管理员。利用此漏洞主要包含以下三个过程:

1. 攻击者构造恶意网页。在实施攻击前,攻击者需要构造一个与正常添加管理员用户基本一样的网页,在该恶意网页中对必要的参数项进行赋值,并将该网页的action指向正常添加管理员用户时访问的URL,核心代码如图2所示;

2. 攻击者利用社会工程学诱使Axous系统管理员访问其构造的恶意网页;

3. 执行恶意代码。当系统管理员访问恶意网页时,恶意代码在管理员不知情的情况下以系统管理员的合法权限被执行,攻击者伪造的管理员账户添加成功。

图2 CSRF攻击添加管理员核心代码

3、CSRF 漏洞检测

检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。

随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。

以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。

4、CSRF漏洞防御

CSRF漏洞防御主要可以从三个层面进行,即服务端的防御、用户端的防御和安全设备的防御。

4.1.服务端的防御

目前业界服务器端防御CSRF攻击主要有三种策略:验证HTTP Referer字段,在请求地址中添加token并验证,在HTTP头中自定义属性并验证。下面分别对这三种策略进行简要介绍。

4.1.1验证HTTP Referer字段

根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。比如某银行的转账是通过用户访问http://bank.test/test?page=10&userID=101&money=10000页面完成,用户必须先登录bank. test,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是转账按钮所在页面的URL(本例中,通常是以bank. test域名开头的地址)。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

4.1.2在请求地址中添加token并验证

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

4.1.3在HTTP头中自定义属性并验证

自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。

4.2.用户端的防御

    对于普通用户来说,都学习并具备网络安全知识以防御网络攻击是不现实的。但若用户养成良好的上网习惯,则能够很大程度上减少CSRF攻击的危害。例如,用户上网时,不要轻易点击网络论坛、聊天室、即时通讯工具或电子邮件中出现的链接或者图片;及时退出长时间不使用的已登录账户,尤其是系统管理员,应尽量在登出系统的情况下点击未知链接和图片。除此之外,用户还需要在连接互联网的计算机上安装合适的安全防护软件,并及时更新软件厂商发布的特征库,以保持安全软件对最新攻击的实时跟踪。

4.3.安全设备的防御

由于从漏洞的发现到补丁的发布需要一定的时间,而且相当比例的厂商对漏洞反应不积极,再加之部分系统管理员对系统补丁的不够重视,这些都给了攻击者可乘之机。鉴于上述各种情况,用户可以借助第三方的专业安全设备加强对CSRF漏洞的防御。

CSRF攻击的本质是攻击者伪造了合法的身份,对系统进行访问。如果能够识别出访问者的伪造身份,也就能识别CSRF攻击。研究发现,有些厂商的安全产品能基于硬件层面对HTTP头部的Referer字段内容进行检查来快速准确的识别CSRF攻击。图3展示了这种防御方式的简图。目前H3C公司的IPS产品采用了特殊技术,支持对部分常用系统的CSRF漏洞攻击进行检测和阻断。

图3 安全设备传统防御方式

5、结束语

CSRF攻击作为一种存在已久的攻击方式,在大量的商业网站上都可以找出。对广大系统维护者来说需要深入理解CSRF攻击,并制定最适合当前系统的防御方案,在不损害应用程序性能的前提下,提高系统安全性;而对即将开发的网络应用系统来说,深刻理解CSRF的危害性,在设计阶段就考虑到对CSRF的防范将会取得事半功倍的效果。



Understanding CSRF

The Express team's csrf and csurf modulesfrequently have issues popping up concerned about our usage of cryptographic functions.These concerns are unwarranted due to a misunderstanding of how CSRF tokens work.So here's a quick run down!

Read this and still have questions? Want to tell us we're wrong? Open an issue!

How does a CSRF attack work?

On their own (phishing site), an attacker could create an AJAX button or form that creates a request against your site:

<form action="https://my.site.com/me/something-destructive" method="POST">
  <button type="submit">Click here for free money!</button>
</form>

This is worse with AJAX as the attacker could use other methods like DELETE as well as read the result.This is particularly important when the user has some sort of session with very personal details on your site.If this is in the context of a technologically illiterate user,there might be some inputs for credit card and social security info.

How to mitigate CSRF attacks?

Use only JSON APIs

AJAX calls use JavaScript and are CORS-restricted.There is no way for a simple <form> to send JSON,so by accepting only JSON,you eliminate the possibility of the above form.

Disable CORS

The first way to mitigate CSRF attacks is to disable cross-origin requests.If you're going to allow CORS,only allow it onOPTIONS, HEAD, GET as they are not supposed to have side-effects.

Unfortunately, this does not block the above request as it does not use JavaScript (so CORS is not applicable).

Check the referrer header

Unfortunately, checking the referrer header is a pain in the ass,but you could always block requests whose referrer headers are not from your site.This really isn't worth the trouble.

For example, you could not load sessions if the referrer header is not your server.

GET is always idempotent

Make sure that none of your GET requests change any relevant data in your database.This is a very novice mistake to make and makes your app susceptible to more than just CSRF attacks.

Avoid using POST

Because <form>s can only GET and POST,by using other methods like PUTPATCH, and DELETE,an attacker has fewer methods to attack your site.

Don't use method override!

Many applications use  method-override to usePUTPATCH, and DELETE requests over a regular form.This, however, converts requests that were previously invulnerable vulnerable!

Don't use method-override in your apps - just use AJAX!

Don't support old browsers

Old browsers do not support CORS or security policies.By disabling support for older browsers(which more technologically-illiterate people use, who are more (easily) attacked),you minimize CSRF attack vectors.

CSRF Tokens

Alas, the final solution is using CSRF tokens.How do CSRF tokens work?

  1. Server sends the client a token.
  2. Client submits a form with the token.
  3. The server rejects the request if the token is invalid.

An attacker would have to somehow get the CSRF token from your site,and they would have to use JavaScript to do so.Thus, if your site does not support CORS,then there's no way for the attacker to get the CSRF token,eliminating the threat.

Make sure CSRF tokens can not be accessed with AJAX!Don't create a /csrf route just to grab a token,and especially don't support CORS on that route!

The token just needs to be "unguessable",making it difficult for a attacker to successful within a couple of tries.It does not have to be cryptographically secure.An attack is one or two clicks by an unbeknownst user,not a brute force attack by a server.

BREACH attack

This is where the salt comes along.The BREACH attack is pretty simple: if the server sends the same or very similar response over HTTPS+gzip multiple times,an attacker could guess the contents of response body (making HTTPS utterly useless).Solution? Make each response a tiny bit different.

Thus, CSRF tokens are generated on a per-request basis and different every time.But the server needs to know that any token included with a request is valid.Thus:

  1. Crytographically secure CSRF tokens are now the CSRF "secret", (supposedly) only known by the server.
  2. CSRF tokens are now a hash of the secret and a salt.

Read more here:

Note that CSRF doesn't solve the BREACH attack,but the module simply randomizes requests to mitigate the BREACH attack for you.

The salt doesn't have to be cryptographically secure

Because the client knows the salt!!!The server will send <salt>;<token> and the client will return the same value to the server on a request.The server will then check to make sure <secret>+<salt>=<token>.The salt must be sent with the token,otherwise the server can't verify the authenticity of the token.

This is the simplest cryptographic method.There are more methods, but they are more complex and not worth the trouble.

Creating tokens must be fast

Because they are created on every request!Doing something as simple as Math.random().toString(36).slice(2) is sufficient as well as extremely performant!You don't need OpenSSL to create cryptographically secure tokens on every request.

The secret doesn't have to be secret

But it is.If you're using a database-backed session store,the client will never know the secret as it's stored on your DB.If you're using cookie sessions,the secret will be stored as a cookie and sent to the client.Thus, make sure cookie sessions use httpOnly so the client can't read the secret via client-side JavaScript!

When you're using CSRF tokens incorrectly

Adding them to JSON AJAX calls

As noted above, if you don't support CORS and your APIs are strictly JSON,there is absolutely no point in adding CSRF tokens to your AJAX calls.

Exposing your CSRF token via AJAX

Don't ever create a GET /csrf route in your appand especially don't enable CORS on it.Don't send CSRF tokens with API response bodies.

Conclusion

As the web moves towards JSON APIs and browsers become more secure with more security policies,CSRF is becoming less of a concern.Block older browsers from accessing your site and change as many of your APIs to be JSON APIs,and you basically no longer need CSRF tokens.But to be safe, you should still enable them whenever possible and especially when it's non-trivial to implement.


        最后,对防御 CSRF 提出两种解决方案:
  1. 在每个表单中包含一个 CSRF Token.
  2. 不将用于认证的 Token 或 Seesion ID 储存在 Cookie 中,而是将其储存在 localStorage 中,在每次发起请求时手动将 Token 添加到请求中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值