浏览器原理 33 # CSRF攻击:为什么Cookie中有SameSite属性?
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浏览器原理 33 # CSRF攻击:为什么Cookie中有SameSite属性?相关的知识,希望对你有一定的参考价值。
说明
浏览器工作原理与实践专栏学习笔记
CSRF 攻击的典型案例
关于 David 的域名被盗的完整过程感兴趣的可以看看:David Airey:Google’s Gmail security failure leaves my business sabotaged
比如:里面就提到谷歌 Gmail 缺陷的揭露:
受害者在登录 Gmail 时访问一个页面。执行后,该页面对 Gmail 接口之一执行
multipart/form-data POST
,并将过滤器注入受害者的过滤器列表。在上面的示例中,攻击者编写了一个过滤器,它只是查找带有附件的电子邮件并将它们转发到他们选择的电子邮件。此过滤器将自动传输所有符合规则的电子邮件。请记住,将来的电子邮件也将被转发。攻击将一直存在由于受害者在其过滤器列表中拥有过滤器,即使导致注入的初始漏洞已由 Google 修复。
劫持三步图:
David 域名被盗流程
- David 发起登录 Gmail 邮箱请求
- Gmail 服务器返回一些登录状态给 David 的浏览器,这些信息包括了 Cookie、Session 等
- 黑客通过各种手段引诱 David 去打开他的链接,比如 hacker.com
- 然后在 hacker.com 页面中,黑客编写好了一个邮件过滤器,并通过 Gmail 提供的 HTTP 设置接口设置好了新的邮件过滤功能
- 该过滤器会将 David 所有的邮件都转发到黑客的邮箱中
- 有了 David 的邮件内容,黑客就可以去域名服务商那边重置 David 域名账户的密码,重置好密码之后,就可以将其转出到黑客的账户了
什么是 CSRF 攻击
CSRF 英文全称是
Cross-site request forgery
,又称为“跨站请求伪造”
,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。
简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。
CSRF 攻击的三种方式
假设极客时间具有转账功能,可以通过 POST 或 Get 来实现转账,转账接口如下所示:
#同时支持POST和Get
#接口
https://time.geekbang.org/sendcoin
#参数
##目标用户
user
##目标金额
number
接下来看看这三种方式是怎么实现的?
1. 自动发起 Get 请求
黑客最容易实施的攻击方式是自动发起 Get 请求。
黑客页面的 html 代码:自动发起 Get 请求
<!DOCTYPE html>
<html>
<body>
<h1>黑客的站点:CSRF攻击演示</h1>
<img src="https://time.geekbang.org/sendcoin?user=hacker&number=100">
</body>
</html>
黑客将转账的请求接口隐藏在 img 标签内,欺骗浏览器这是一张图片资源。当页面加载请求图片资源的时候就会调用接口,用户账户上的 100 极客币就被转移到黑客的账户上去。
2. 自动发起 POST 请求
黑客页面的 HTML 代码:自动提交 POST 请求
<!DOCTYPE html>
<html>
<body>
<h1>黑客的站点:CSRF攻击演示</h1>
<form id='hacker-form' action="https://time.geekbang.org/sendcoin" method=POST>
<input type="hidden" name="user" value="hacker" />
<input type="hidden" name="number" value="100" />
</form>
<script> document.getElementById('hacker-form').submit(); </script>
</body>
</html>
这里使用了构建自动提交表单这种方式,自动实现跨站点 POST 数据提交。
3. 引诱用户点击链接
<div>
<img width=150 src="http://images.xuejuzi.cn/1612/1_161230185104_1.jpg" />
<a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_blank">
点击下载美女照片
</a>
</div>
很显然这是利用美色进行诱惑,让用户去点击下载,然后实现接口调用,导致资金的转移。
从面可以看出,和 XSS 不同的是,CSRF 攻击不需要将恶意代码注入用户的页面,仅仅是利用服务器的漏洞和用户的登录状态来实施攻击。
如何防止 CSRF 攻击
CSRF 攻击的三个必要条件:
- 目标站点一定要有 CSRF 漏洞
- 用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态
- 需要用户打开一个第三方站点,可以是黑客的站点,也可以是一些论坛
CSRF 攻击不会往页面注入恶意脚本,而是找服务器的漏洞,因此黑客是无法通过 CSRF 攻击来获取用户页面数据的,对于 CSRF 攻击,主要的防护手段是提升服务器的安全性。
1. 充分利用好 Cookie 的 SameSite 属性
Cookie 是浏览器和服务器之间维护登录状态的一个关键数据。通常 CSRF 攻击都是从第三方站点发起的,要防止 CSRF 攻击,最好能实现从第三方站点发送请求时禁止 Cookie 的发送。
要防止 CSRF 攻击的方案:
- 如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键 Cookie 数据到服务器;
- 如果是同一个站点发起的请求,那么就需要保证 Cookie 数据正常发送。
而 Cookie 中的 SameSite 属性正是为了解决这个问题的。
在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项,如下:
set-cookie: 1P_JAR=2019-10-20-06; expires=Tue, 19-Nov-2019 06:36:21 GMT; path=/; domain=.google.com; SameSite=none
SameSite 选项通常有 Strict、Lax 和 None 三个值。
这里可以参考一下:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie/SameSite
Strict 最为严格。
如果 SameSite 的值是 Strict,那么浏览器会完全禁止第三方 Cookie。简言之,如果你从极客时间的页面中访问 InfoQ 的资源,而 InfoQ 的某些 Cookie 设置了 SameSite = Strict 的话,那么这些 Cookie 是不会被发送到 InfoQ 的服务器上的。只有你从 InfoQ 的站点去请求 InfoQ 的资源时,才会带上这些 Cookie。
Lax 相对宽松一点。
在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交 Get 方式的表单这两种方式都会携带 Cookie。但如果在第三方站点中使用 Post 方法,或者通过 img、iframe 等标签加载的 URL,这些场景都不会携带 Cookie。
None 在任何情况下都会发送 Cookie 数据。
如果还不是很理解,我们可以具体看看:
首先假设你发出登录InfoQ的站点请求,然后在InfoQ返回HTTP响应头给浏览器,InfoQ响应头中的某些set-cookie字段如下所示:
set-cookie: a_value=avalue_xxx; expires=Thu, 21-Nov-2019 03:53:16 GMT; path=/; domain=.infoq.com; SameSite=strict
set-cookie: b_value=bvalue_xxx; expires=Thu, 21-Nov-2019 03:53:16 GMT; path=/; domain=.infoq.com; SameSite=lax
set-cookie: c_value=cvaule_xxx; expires=Thu, 21-Nov-2019 03:53:16 GMT; path=/; domain=.infoq.com; SameSite=none
set-cookie: d_value=dvaule_xxxx; expires=Thu, 21-Nov-2019 03:53:16 GMT; path=/; domain=.infoq.com;
我们可以看出
a_value的SameSite属性设置成了strict,
b_value的SameSite属性设置成了lax
c_value的SameSite属性值设置成了none
d_value没有设置SameSite属性值
这些Cookie设置好之后,当你再次在InfoQ的页面内部请求InfoQ的资源时,这些Cookie信息都会被附加到HTTP的请求头中,如下所示:
cookie: a_value=avalue_xxx;b_value=bvalue_xxx;c_value=cvaule_xxx;d_value=dvaule_xxxx;
但是,假如你从 time.geekbang.org
的页面中,通过a标签打开页面,如下所示:
<a href="https://www.infoq.cn/sendcoin?user=hacker&number=100">点我下载</a>
当用户点击整个链接的时候,因为InfoQ中a_vaule的SameSite的值设置成了strict,那么a_vaule的值将不会被携带到这个请求的HTTP头中。
如果 time.geekbang.org
的页面中,有通过img来加载的infoq的资源代码,如下所示:
<img src="https://www.infoq.cn/sendcoin?user=hacker&number=100">
那么在加载infoQ资源的时候,只会携带c_value,和d_value的值。
现在应该基本清楚这个 SameSite 设置不同值的意思了,关于使用方式可以参考下面的文章
SameSite 的具体使用方式:https://web.dev/samesite-cookies-explained/
根据上面对 SameSite 的了解,在防范 CSRF 攻击时,可以针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式,这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。
2. 验证请求的来源站点
怎么判断请求是否来自第三方站点呢?
- Referer 是 HTTP 请求头中的一个字段,记录了该 HTTP 请求的来源地址。
比如:从极客时间的官网打开了 InfoQ 的站点:可以看到 HTTP 请求头中的 Referer 引用
对于有一些场景是不适合将来源 URL 暴露给服务器的,浏览器提供给开发者一个选项,可以不用上传 Referer 值,具体可参考 Referrer Policy。
- 在服务器端验证请求头中的 Referer 并不是太可靠,因此标准委员会又制定了 Origin 属性,Origin 属性只包含了域名信息,并没有包含具体的 URL 路径
比如:通过 XMLHttpRequest、Fecth 发起跨站请求或者通过 Post 方法发送请求时,都会带上 Origin 属性
Origin 的值之所以不包含详细路径信息,是有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器。另外服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。
3. CSRF Token
- 在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。
CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。
<!DOCTYPE html>
<html>
<body>
<form action="https://time.geekbang.org/sendcoin" method="POST">
<input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
<input type="text" name="user">
<input type="text" name="number">
<input type="submit">
</form>
</body>
</html>
- 在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。
如果是从第三方站点发出的请求,那么将无法获取到 CSRF Token 的值,所以即使发出了请求,服务器也会因为 CSRF Token 不正确而拒绝请求。
总之,陌生链接不要随便点。
以上是关于浏览器原理 33 # CSRF攻击:为什么Cookie中有SameSite属性?的主要内容,如果未能解决你的问题,请参考以下文章