web安全之CSRF

CSRF是什么

CSRF(Cross Site Request Forgery)跨站请求伪造,是一种攻击方式。通过名字可以看出这个攻击通常是在其他网站发出的,并不是在目标网站

该攻击会在用户不知情的情况下盗用用户的登录信息请求目标网站完成对目标网站数据库信息的修改,所以需要防范CSRF的接口只需要是修改数据的接口,对于获取信息的接口则没有这个必要。

CSRF和XSS不一样,CSRF只可以盗用用户的身份但是由于浏览器同源限制不能获取用户信息,但是XSS漏洞如果存在的话那么用户信息是存在泄漏风险的。

跨域请求的限制只存在于Ajax请求中,也就是说表单的提交没有登录验证的话是可以从a.com提交信息到b.com,b.com的服务端会把从a.com提交过来的数据写入到数据库中。即使需要登录b.com才能提交表单,那么在b.com登录之后,登录态写在b.com域名下的cookie中。很不幸的是这时候还是可以从a.com提交信息到b.com。因为向b.com发送http请求的时候b.com域名下的cookie(刚才在b.com下登录后储存了登录态)是会被带过去的,这样b.com验证是否登录就会发现身份合法,但是其实是a.com发过来的请求,并不是b.com,甚至用户都不知道这个请求发生了,只要你访问了a.com会有很多方法在用户不知道的情况下发送这个请求。

上面的描述中a.com就完成了一次对b.com的CSRF攻击。

完整描述一个案例(来自https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/

受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。

怎么防御

既然知道了CSRF的原理,那么就来说说怎么防御这个类型的攻击。

referer

通过上面的描述可以看出CSRF发起的请求并不是在目标网页上,请求来自哪个域名HTTP请求头部会有一个字段(Referer)的值会标识出来。服务端可以通过这个字段来辨别发过来的请求的域名是否是自己,如果不是自己另做处理,如果是自己则正常处理。

但是这个方法也不是万无一失的,请求头的字段在某些浏览器通过某些手段是可以修改的,这样的话就还是有问题。通过这个问题告诉我们,自身的安全依赖第三方还是不靠谱。

tooken

因为CSRF是在其他网站发起请求完成的攻击,那么发起攻击的网站是获取不到目标网站页面上信息的。那么如果我们将一个tooken放在页面上,发起请求的时候都需要带上这个tooken不就解决这个问题了吗。

通常是用脚本完成链接tooken的添加,如果是GET请求在search里面加上tooken字段和对应的值。如果是POST请求的form就新建一个hidden的input放在form里面,提交的时候就会自动带上。

但是这样还有一个问题。想想一下这个场景,不法者通过b.com的一个发布一个连接是a.com这样的话是不是在页面上动态添加tooken的时候也会为a.com加上,这样你点击这个链接进去之后a.com还是可以获取到b.com页面上的tooken,还是可以让tooken验证通过完成攻击。所以添加tooken的时候需要验证这个域名是不是自己的。

即使这样了还存在一个缺陷,这样添加的tooken只在已有的DOM上才加了,如果是通过JS后期插入的链接是还是没有tooken即使这个链接是合法的,所以添加有链接的DOM的时候需要再添加一次tooken。

在HTTP头中添加自定义属性

这个方式有一定的局限性,只能用在Ajax中,也就是说要改写整个网站的请求发送方式为Ajax。对于传统网站代价大点,但是对于单页的网站几乎就没有成本了。

这中方式也是利用tooken,然后在服务端验证这个字段中的tooken来判断是否是合法请求。这种方式避免了上面直接在链接中加入tooken的一些缺点,这样发送的请求不会被浏览器记住。

不要点来历不明的链接,好奇害死猫。

参考

CSRF 攻击的应对之道

猜你喜欢

转载自blog.csdn.net/letterTiger/article/details/82385813