AFAIK,我们将 CSRF 定义为安全漏洞,恶意攻击者使用各种脚本,在未经用户同意的情况下,使用户执行特定于用户的操作。例如,我们的恶意攻击者诱使用户进入运行以下代码的网站来更改用户的电子邮件地址。
<form action="https://examplefornonsafewebsite.com/email/change" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>
在这种情况下,如果网站没有 CSRF 保护,则用户的电子邮件地址将因用户采取的操作而在未经用户同意的情况下被更改。我的问题是,“CSRF 令牌与会话 cookie 的区别是什么?”当恶意攻击者进行用户更改时,如何访问会话 cookie 而不能访问 CSRF 令牌?毕竟,既然这是从用户的浏览器完成的,那么 CSRF 令牌不应该也可以访问吗?
会话cookie应该是HttpOnly,然后不能通过Javascript访问,但它会自动包含在对发出它的
examplefornonsafewebsite.com
域的每个请求中。
为了确保
examplefornonsafewebsite.com
网页安全,必须在发出 POST 请求之前获取 CSRF 令牌。该令牌仅在与会话 cookie 结合(“绑定到”)时才有效并获得
<form>
加载 https://examplefornonsafewebsite.com/email/form
并且其中包含 <input type="hidden" name="X-CSRF-Token" value="..."/>
fetch("https://examplefornonsafewebsite.com/email/gettoken")
发出 GET 请求并从响应中读取 CSRF 令牌。该令牌必须包含在后续的 POST 请求中fetch("https://examplefornonsafewebsite.com/email/change", {
method: "POST",
headers: {"Content-Type": "x-www-form-urlencoded"},
body: "[email protected]&X-CSRF-Token=..."
})
examplefornonsafewebsite.com
网页可以使用任一选项在发出电子邮件更改请求时包含 CSRF 令牌。
但这两种选择对于攻击者来说都是不可能的:在第一个选项中,浏览器已经导航到
examplefornonsafewebsite.com
网页,并且攻击者的页面不再参与。
在第二个选项中,攻击者的页面可以发出
fetch
请求,但无法读取响应,因为这是一个 跨域 (CORS) 请求:它是由攻击者网站的 Javascript 发出的页面但转到不同的原点https://examplefornonsafewebsite.com/
。然后,由于响应不包含 Access-Control-Allow-Origin
标头,因此 fetch
请求会被拒绝并显示“TypeError: Failed to fetch”,并且攻击者无法读取 CSRF 令牌。
重要的是,如果攻击者在攻击之前尝试获取 CSRF 令牌(通过使用自己的浏览器向
https://examplefornonsafewebsite.com/email/gettoken
发出请求),他们可能会得到一个,但它不会绑定到受害者的会话 cookie,因此将毫无价值。
总结一下: 会话 cookie1 无法通过 Javascript 访问,无论是攻击者还是合法网页都无法访问,但无论如何都会由浏览器发送。借助 CORS 协议,CSRF 令牌只能由合法网页获取。只有将两者结合起来才能确保
examplefornonsafewebsite.com
(否则CORS协议将阻止获取CSRF令牌)。CSRF保护机制因此依赖于CORS。
1 即使相关 cookie 不是会话 cookie,此机制也能正常工作,请参阅在身份验证之前应该提供 CSRF 保护令牌吗?