使用 Same-Site Cookie 属性防止 CSRF 攻击
介绍 Web Cookies
因为 HTTP 是一种无状态协议,所以它无法在内部区分不同用户。为了解决这个问题,cookie 技术于 1994 年发明。通过使用 cookie,服务器指示浏览器保存一个唯一的密钥,然后将其与向服务器发出的每个请求一起发送回。
当请求从浏览器发送到网站时,浏览器会检查是否有属于该网站的存储 cookie。在执行此过程时,它会检查 cookie 的属性和标志(域、路径、安全)是否与请求的网站数据相匹配。如果匹配,浏览器会将相关 cookie 与请求一起发送。
Cookie 滥用可能导致跨站点请求伪造
对于第三方通过浏览器发出的请求,也会以相同的方式重复这种行为。我们所说的“第三方”是指我们不直接访问的其他网站。从网络应用安全的角度来看,关键一点是,当你访问网站 A 时,浏览器中为网站 B 保存的所有 cookie 都将添加到网站 A 向网站 B 发起的请求中。因此,浏览器上属于 B 的 session 可能会被使用,甚至被滥用。
在安全术语中,这种滥用浏览器的行为被称为跨站点请求伪造(CSRF)。它是通过使用这种浏览器行为滥用属于授权用户的 session 来实现的。
这种浏览器行为也可能被滥用于其他目的,如跟踪用户或广告。当你进入一个网站,例如 example.com 时,由于 example.com 页面上的 HTML 元素,例如 Facebook Like 按钮、谷歌分析代码等,你的浏览器可能会向不同的网站发出一些请求。除了这些请求,浏览器中属于这些其他网站的 cookie 也会被发送。因此,这些第三方可以使用 Cookie 和 Referrer 信息来跟踪和记录你的活动。
是否应该阻止跨站点请求以阻止 CSRF?
通常情况下,在 Firefox 和 Chrome 浏览器中可以避免这样的跟踪。然而,当这些浏览器阻止跟踪时,它们会阻止任何第三方网站在发送请求时发送 cookie。但是这样做的话,你的浏览体验会很差。因此,通过阻止 cookie,你可以完全阻止 CSRF,但这值得吗?
引入 Same-Site Cookie 属性以防止 CSRF 攻击
多亏了 cookie 安全标志,现在有了一个解决方案。它被称为 Same-Site cookie 属性。开发人员现在可以指示浏览器通过使用 SameSite cookie 属性来控制 cookie 是否与第三方网站发起的请求一起发送,这是一个比拒绝发送 cookie 更实用的解决方案。
为 cookie 设置 Same-Site 属性非常简单。它只包括向 cookie 中添加一条指令。只需添加 “SameSite=Lax” 或 “SameSite=Strict” 就足够了!
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
SameSite Cookie属性的 Strict 和 Lax 之间的差异
Strict: 顾名思义,这是严格应用“同一站点”规则的选项。当 SameSite 属性设置为 Strict 时,cookie 将不会与第三方网站发起的请求一起发送。
将 cookie 设置为 “Strict” 会对浏览体验产生负面影响。例如,如果点击指向 Facebook 个人资料页面的链接,并且 Facebook.com 已将其 cookie 设置为 SameSite=Strict,则除非再次登录 Facebook,否则您无法继续在 Facebook 上导航(查看 Facebook 页面)。这是因为 Facebook 的 cookie 不是通过这个请求发送的。
Lax: 当将 cookie 的 SameSite 属性设置为 Lax时,cookie 将与第三方网站发起的 GET 请求一起发送。
这里的重要一点是,要发送带有 GET 请求的 cookie,所发出的 GET 请求必须引起顶级导航。只有这样,设置为 LAX 的 cookie 才会被发送。让我来详加解释。
可以通过 iframe、img 标记和 script 标记加载资源。这些请求也可以作为 GET 请求操作,但它们都不会使其成为顶级导航。基本上,他们不会更改地址栏中的 URL。因为这些 GET 请求不会使其成为顶级导航,因此设置为 Lax 的 cookie 不会与它们一起发送。
有关详细说明,请参阅下表:
Request Type | Example Code | Cookies sent |
Link | <a href=”…”></a> | Normal, Lax |
Perender | <link rel=”prerender” href=”..”/> | Normal, Lax |
Form GET | <form method=”GET” action=”…”> | Normal, Lax |
Form POST | <form method=”POST” action=”…”> | Normal |
iframe | <iframe src=”…”></iframe> | Normal |
AJAX | $.get(“…”) | Normal |
Image | <img src=”…”> | Normal |
这真的意味着不会有 CSRF 吗?
是的,看起来 SameSite cookie 属性是抵御 CSRF 攻击的有效安全措施。通过使用此功能,你可以避免将 cookie 与第三方发起的请求一起发送。让我举例说明:
假设您已登录到网站 www.badbank.com。使用网络钓鱼攻击,攻击者可以诱使您在另一个浏览器选项卡中输入 www.attacker.com。攻击者使用 www.attacker.com 上的代码,试图通过向 www.badback.com 提交表格从你的帐户转账。你的浏览器会发送属于 www.badbank.com 的 cookie 并发出此请求。如果 www.badbank.com 上的表单缺少防止 CSRF 攻击的 CSRF 令牌,则攻击者可能会利用你的 session。
如果 www.badbank.com 的 cookie 设置为 SameSite=Lax,浏览器中的 cookie 将不会与 POST 请求一起发送,攻击也不会成功。
CSRF 排名下降
CSRF 攻击在 2010 年公布的 OWASP 前十名中排名第五,但在 2013 年的 OWASP 十名中下降到第八。人们认为,这是因为人们对 CSRF 的认识提高,以及框架对反 CSRF token 的普遍使用。
来源 : https://www.owasp.org/index.php/Top_10_2013-Release_Notes
防止 CSRF 漏洞
尽管我们现在使用 SameSite Cookie 属性,但我们仍然应该谨慎!我们应该使用 POST 请求而不是 GET 来进行整个更改。
GET 是为导航目的而设计的,而不是为了更改状态,因此使用 GET 请求通常被认为是一种安全的方法。然而,当我们执行操作(例如订购产品、更改密码或编辑配置文件信息)时,使用 POST 请求要安全得多。
这有三个重要原因:
- 当参数由 GET 携带时,它们将保留在浏览器历史记录中。它们还将被放置在服务器日志和向第三方发出的请求中的 Referrer 标头中。
- 不使用 GET 请求的另一个原因是,设置为 Lax 的 cookie 仍然与 GET 请求一起发送,这给攻击者提供了另一个利用用户的机会。
最后,通过使用 GET 来利用 CSRF 漏洞要容易得多。要利用使用 GET 的表单中的 CSRF 漏洞,攻击者不必拥有网站。他可以将这个有效载荷注入论坛消息、帖子评论或图片标签中。