• 如何防御跨站请求伪造(CSRF)攻击?
  • 发布于 1个月前
  • 85 热度
    0 评论

CSRF 英文全称是 Cross-site request forgery,所以又称为“跨站请求伪造”,是指恶意诱导用户打开被精心构造的网站,在该网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 就是利用了用户的登录状态,并通过被精心构造的网站利用用户正常网站的会话状态来做用户不知情的事情。


用GET请求
特别典型的目前少见。一个变体我就遇到过:我不小心登录了一个游戏网站,游戏网站不断给我弹出图片要我充钱。我点击关闭,但是这个点击动作触发了一个操作
<img src=http://www.手机话费.com/transfer?to=恶意游戏网站&money=100>
扣了我的话费。这个没有经过我的允许。我懂得维权,于是打电话给运营商:电信、移动或者联通。找客服把话费要回来了。客服说这是我自己的操作,但是为了提高用户体验,还是把话费退给我。客服这么说到底是知道那个平台是有问题的,影响了客户权益,怕影响声誉不肯承认;还是为了解决问题不得而知,但运营商的这个接口是有问题。

我回忆了一下,当时是怎么回事。模糊的记得,注册时用的是手机号验证码自动注册登录。很可能是这时候登录了运营商的网站,当时没有太在意页面是哪个网站的。这个游戏网站用了运营商存储在客户端的cookie信息,向运营商发起伪造请求。这个问题很好解决,对于话费扣除这样重要的接口,运营商不应该用GET请求,用POST并且要求一些信息数据。增加伪造成本。

SameSite属性
上面的场景,我并不确定当时的请求是GET请求,因为毕竟在手机上也没想到看源码。如果运营商那边还没有那么降智,游戏那边花了些力气,模拟表单提交POST请求,怎么来解决呢?

模拟请求的原理是截获了客户端的cookie,Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。它可以设置三个值。

Strict:完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

Lax:规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。

None:网站可以选择显式关闭SameSite属性,将其设为None。前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
Set-Cookie: widget_session=abc123; SameSite=None; Secure
SameSite属性防止攻击的方法,提前是浏览器要支持。服务端还是需要对自己的接口负责。有下面几种方式:
标志请求来源
限制 HTTP 请求头中的 Referer 字段,这个值将在浏览器页面上发起请求时被主动添加,用于指定请求的来源页面。作为网站开发者,我们限制 Referer 请求头,仅允许它来自我们已知的正常地址,而阻止恶意请求。

CSRF Token
服务端生成一个token,浏览器接收到这个Token后存储在本地存储中,提交表单时,会将这个token再传回服务端作比较,比较一致才可以执行。

提交验证码
在表单中增加一个随机的数字或字母验证码,通过强制用户和应用进行交互,来有效地遏制CSRF攻击。

在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。

同域安全策略
CORS,全称Cross-Origin Resource Sharing,是一种允许当前域(domain)的资源被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。Origin字段用来说明,本次请求来自哪个源(协议+域名+端口)。服务器根据这个值,决定是否同意这次请求。不在许可范围内:正常的HTTP回应,响应头不会添加Access-Control-Allow-Origin。origin在许可范围内,响应头会添加Access-Control-xx。
Access-Control-Allow-Origin: http://brmayi.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的请求,否则就报错。
用户评论