一,过去
跨站请求伪造,也称为CSRF或XSRF, 它源于网站必须向另一个站点发出请求的简单功能。
假设我在 https://a.com 面中嵌入了以下表单。
<form action="https://your-bank.com/transfer" method="POST" id="stealMoney">
<input type="hidden"name="to"value="Scott Helme">
<input type="hidden"name="account"value="14278935">
<input type="hidden"name="amount"value="£1,000">
</form>
你的浏览器加载此页面,结果是上面的表单,然后我在页面上使用一个简单的JS提交。
document.getElementById("stealMoney").submit();
我正在伪造一个跨站点发送请求到您的银行。这里真正的问题不是我发送了请求,而是您的浏览器会发送您的 cookie。 该请求将把您当前持有的全部权限一并发送,这意味着如果您已登录到您的银行,您就向我转账了1,000英镑。 如果您没有登录,那么请求将是无害的,因为您无法在未登录的情况下转账。
之前,您的银行可以通过几种方式来缓解这些CSRF攻击:
1,转账前需要验证码
2,检查来源(Origin)
3,Anti-CSRF令牌
二,现在:SameSite 属性
Chrome 51 开始,浏览器的 Cookie 新增加了一个 SameSite 属性,用来防止 CSRF 攻击和用户追踪。它可以设置三个值:Strict、Lax 和 None。
1 Strict
Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
这个规则过于严格,可能造成非常不好的用户体验。比如,如果我提供了 https://facebook.com 的链接,并且Facebook将SameSite cookie设置为严格模式,当您单击链接到打开Facebook时,无论您是否已登录,在新标签页中打开它,从该链接访问时都不会登录到Facebook。
类似于亚马逊做的,他们有2个cookie。一种是一种“基本”cookie,可以将您识别为用户,并允许您拥有登录体验,但如果您想做一些敏感的事情,比如购买或更改帐户中的内容,则需要第二个cookie, “真正的”cookie,可以让你做重要的事情。
2 Lax
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。其他都不会发送请求,比如 POST 表单,iframe,Ajax,img 标签的 src 加载。所以说设置了 Strict 或 Lax 以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。
3 None
Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
下面的设置无效:
Set-Cookie: widget_session=abc123; SameSite=None
下面的设置有效:
Set-Cookie: widget_session=abc123; SameSite=None; Secure
三,时代的眼泪
这也是为什么打开 koa-csrf 的 npm 页面,提示:
四,浏览器支持情况
参考:
https://www.npmjs.com/package/koa-csrf
https://scotthelme.co.uk/csrf-is-dead/
https://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
修改时间 2024-09-29