CSRF 基本上是关于攻击者通过 cookie 在浏览器中的工作方式利用用户的现有会话。根本的问题是,无论请求来自何处(哪个来源,即域)来自,cookie都会随请求一起发送,唯一重要的是它去往到时间>。因此,如果有用户登录到应用程序(具有会话 cookie),攻击者可能会尝试让该用户访问他的恶意网站,攻击者可以从那里使用用户的凭据向应用程序域发出请求(通过完全将用户发布到应用程序,或者更巧妙地通过创建 ajax 请求)。
请注意,这仅适用于应用程序中的身份验证基于浏览器自动发送的内容的情况,最明显的是会话 cookie,但例如基本的 http 身份验证或客户端证书身份验证也可能存在漏洞。此外,CSRF 仅适用于更改某些内容(状态或数据)的请求。
有一件重要的事情在起作用,同源策略 (SOP) 是浏览器。稍微简化一下,这意味着如果从一个域(或更准确地说:源)下载某些内容,那么另一个域将无法访问。
因此,为了防止上述攻击并防止他自己域上的攻击者让用户向用户登录的应用程序发送不需要的请求,可能有几种不同的策略。
同步器令牌
应用程序生成一个 csrf 令牌,将其存储在用户的会话(服务器端)中,并将其发送给客户端,例如将其写入隐藏字段中的每个表单中,或者写入 Javascript 可以使用的单个字段中从中读取并添加到请求中。这是可行的,因为其域中的攻击者无法使用用户会话中的有效令牌创建表单或请求,并且攻击者也无法从应用程序页面读取令牌。当然,攻击者可以尝试下载申请表来获取令牌,但随后他需要凭据。攻击者需要有效的用户会话和相应的 csrf 令牌。攻击者可能拥有自己的适当帐户来登录,但无论如何他都可以执行操作。或者他可能有一个 csrf 令牌,但要么未经身份验证,要么使用较低权限的帐户。但他不能两者兼得,这就是重点。
因此,这种保护基本上验证了请求来自实际由合法应用程序而不是其他人呈现的源。
请注意,在这种情况下,在 cookie 中设置令牌是没有意义的,因为 cookie 会像会话 cookie 一样自动发送。
双重发布
另一种策略是生成一个令牌,并将其设置为客户端的 cookie。然后,客户端从 cookie 中读取令牌,并将相同的令牌作为请求标头发送。服务器只比较请求头和cookie是否包含相同的token。这是可行的,因为攻击者无法从不同来源设置的 cookie 中读取应用程序令牌(参见上面的 SOP),但合法域上的应用程序可以。所以发送请求的客户端有效地证明了它是在合法的应用程序域上运行的。这样做的好处是应用程序是无状态的,不需要会话。缺点是它的安全性稍差。
(有趣的是,这种情况下的令牌甚至可以在客户端生成,它仍然有效,因为他自己的域上的攻击者无法设置或读取应用程序域 cookie,但它肯定不太安全,因为它是一个加密在浏览器中操作。)
检查引用者或来源
正如您正确指出的那样,另一种策略可能是检查请求的引用者或来源。它基本上可以工作,但被认为不太安全。虽然对于许多应用程序来说,双重发布被认为足够安全,但引用/来源检查大多不是。我认为它有很强的历史元素,但它确实不太安全。
这个问题有很多方面,我想到了一些:
- 攻击者在自己的域上发送引用/来源标头can be prevented。所以应用程序不会知道它是一个不同的域 - 它只是没有信息。您当然可以以需要引用和/或来源的方式实现它,但这会导致潜在的错误和问题,浏览器由于某种原因不发送它等。
- 在某些情况下可以伪造引用和来源。例如,旧的易受攻击的浏览器插件(Java、Flash...还有人记得 Flash 吗?)允许设置任何标头,攻击者只需在受害者浏览器中安装其中一个 - 并且每个人都拥有它们。
- 浏览器扩展还可以设置/修改标头,因此攻击者可能会尝试让受害者用户安装他的恶意扩展。
- Origin 仅由现代浏览器设置。现在问题不大了,大多数人使用的浏览器同时设置了引用者和来源。
因此,由于这些原因,简单地检查 referer/origin 不是很健壮,应该设置另一层保护。
SameSite cookie
Google 在 Chrome 中的一项新发明是 cookie 的 SameSite 属性(除了已经存在且广泛使用的 httpOnly 和 secure cookie 属性)。目前只支持Chrome,其他浏览器不支持。
如上所述,根本问题是 cookie(即会话 cookie)是根据请求目标而不是来源发送到服务器的。这意味着如果攻击者.com 为用户提供一个页面,并且该页面从浏览器向 legitapp.com 发送一个发布请求,那么由 legitapp.com 设置的任何 cookie 都将被发送到 legitapp.com。所以如果是登录legitapp.com的用户访问attacker.com,现有的会话就可以被利用。
这由SameSite cookie attribute 更改,当源域与目标域不同时,不会发送cookie。它可以设置为 'strict' 或 'lax',这基本上决定了 GET 请求行为,但其中任何一个都会阻止 CSRF
非 GET 请求。