CSRF Token 的设计是否有其必要性?
CSRF Token 确实会对网站安全起到一些积极作用,但我想讨论 CSRF Token 对于一个网站是否是必要的。
例如如果已经要求所有非幂等的请求都用 POST 方法提交,是否 CSRF Token 就不必要了呢?
CSRF 和 CORS 的关系又是怎样的呢?
感谢大家的回答,我已经理解了这个问题,我也惊讶于我对这个问题的理解一直以来都是错误的。但我觉得对于我的疑问,大家的回答都不是很恰当,因此我自己来回答一下这个问题。
我之前错误的理解是「form 和 XHR 发起的 POST 请求都受到 CORS 的限制,因此只要非幂等请求不是 GET, 就可以防范 CSRF」,而我今天才发现,原来 form 发起的 POST 请求并不受到 CORS 的限制,因此可以任意地使用其他域的 Cookie 向其他域发送 POST 请求,形成 CSRF 攻击。
我还针对这个问题请教了 @c4605 , 他对防御 CSRF 提出了两种解决方案:
- 在每个表单中包含一个 CSRF Token.
- 不将用于认证的 Token 或 Seesion ID 储存在 Cookie 中,而是将其储存在 localStorage 中,在每次发起请求时手动将 Token 添加到请求中。
其中我比较偏好第二种解决方案,似乎各位并没有提到,因此在这里与大家分享一下。
Answers
CSRF 攻击的对象
在讨论如何抵御 CSRF 之前,先要明确 CSRF 攻击的对象,也就是要保护的对象。从以上的例子可知,CSRF
攻击是黑客借助受害者的 cookie 骗取服务器的信任,但是黑客并不能拿到 cookie,也看不到 cookie
的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。因此,黑客无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。所以,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行
CSRF 的保护。比如银行系统中转账的请求会直接改变账户的金额,会遭到 CSRF
攻击,需要保护。而查询余额是对金额的读取操作,不会改变数据,CSRF 攻击无法解析服务器返回的结果,无需保护。
http://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
由此,GET 請求不需要 CSRF Token(因爲寫操作不應該用 GET),POST 請求在執行寫操作時依舊需要 CSRF Token。
提醒下题主,第三方恶意网站也是可以构造post请求并提交至被攻击网站的,所以POST方式提交只是提高了攻击的门槛而已,无法防范CSRF攻击,防范CSRF攻击中token的作用:
CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
题主可以看下这篇文章:《 CSRF 攻击的应对之道 》
CSRF 是什么?
Cross-site request forgery 跨站请求伪造,也被称为 “one click attack” 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。
CSRF 攻击类似 XSS 攻击,都是在页面中嵌入特殊部分引诱或强制用户操作从而得到破坏等的目的,区别就是迫使用户
访问特定 URL / 提交表单
还是执行 javascript 代码。
为什么叫
跨站请求
攻击?
从字面意思就可以理解:当你访问
fuck.com
黑客页面的时候,页面上放了一个按钮或者一个表单,URL/action 为
http://you.com/delete-myself
,这样引导或迫使甚至伪造用户触发按钮或表单。在浏览器发出 GET 或 POST 请求的时候,它会带上
you.com
的 cookie,如果网站没有做 CSRF 防御措施,那么这次请求在
you.com
看来会是完全合法的,这样就会对
you.com
的数据产生破坏。
如何防止 CSRF ?
CSRF 主流防御方式是在后端生成表单的时候生成一串随机 token ,内置到表单里成为一个字段,同时,将此串 token 置入 session 中。每次表单提交到后端时都会检查这两个值是否一致,以此来判断此次表单提交是否是可信的。提交过一次之后,如果这个页面没有生成 CSRF token ,那么 token 将会被清空,如果有新的需求,那么 token 会被更新。
攻击者可以伪造 POST 表单提交,但是他没有后端生成的内置于表单的 token,session 中有没有 token 都无济于事。