在 Angular 中使用持久性 XSRF-TOKEN cookie 的风险
Risk of using a persitent XSRF-TOKEN cookie in Angular
这与这个问题有关CSRF Protection for Refresh Token Cookie in SPA
我想使用推荐的 XSRF-TOKEN
cookie 机制来保护另一个 HttpOnly cookie。对于这种情况,我需要使 XSRF-TOKEN
cookie 持久化,因为它必须在应用程序重新加载后启动时可用。 Angular $http
中的默认实现仅在 session 个 cookie 中查找。
如果我使 cookie 持久化并手动设置 X-XSRF-TOKEN
HTTP header 有什么风险?
如果您选择使用持久性 cookie,您仍然容易受到 CSRF 攻击,因为浏览器会随请求发送这些 cookie
对于 angularjs,以下是我在我的 SPA 应用程序中使用的内容; CSRF 令牌由后端服务器生成,并仅在对 index.html
文件的请求中作为 header 传递。从那时起,angular 被配置为在 header + session cookie 中添加令牌 - 对于每个内部 $http.post/delete/put/...
请求
app.config(['$httpProvider', function ($httpProvider)
{
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
测试一下
使用这个小片段手动测试您的 api:
<!DOCTYPE html>
<html>
<head>
<script>
function csrf(id)
{
document.getElementById("csrf-form-" + id).submit();
}
</script>
</head>
<body>
<form method="POST" action="http://127.0.0.1:8080/api/test" enctype="text/plain" target="_blank" id="csrf-form-1">
<input name='{"protected":false, "ignore_me":"' value='test"}'type='hidden'>
</form>
<button onclick="csrf(1)"}>CSRF!</button>
</body>
</html>
CSRF 攻击在用户登录的不受保护的站点上起作用。考虑使用会话 cookie C(仅此而已)来识别用户会话的站点 S。这意味着浏览器将在每次向 S 发送请求时发送 C。由于会话 cookie 的存在是确认会话所需的全部内容,因此用户将在访问 S 时登录。这很好。正是我们想要的。
除了...
我们假设 S can 是一个可以通过 URL(例如 https://S/email-cash?email=recipient@examplecom
)通过电子邮件发送现金的网站。一个邪恶的网站 E 可以在其页面之一中嵌入 link https://S/email-cash?email=ATTACKER@examplecom
。现在,当用户在登录站点 S 的同时浏览站点 E 并单击此 link 时,他们最终会通过电子邮件向攻击者发送钱款。更糟糕的是,这个 link 可以在 JavaScript 幕后执行,因此用户只需访问站点 E。非常糟糕。
问题的发生是因为每个带有有效会话 ID cookie C 的请求都被视为有效请求。解决方案是要求浏览器发送一些它只能最近从站点 S 获得的 ID。这就是 CSRF 令牌。浏览器无法获取它,除非它由 S 提供,并且 S 只会在它提供页面时提供它,而不是用于跨站点攻击。
现在,如果您开始将 CSRF 令牌存储为持久性 cookie,它会破坏整个目的,因为它成为浏览器可以在跨站点攻击中发送的东西。
What are risks if I make the cookie persistent and manually set the
X-XSRF-TOKEN HTTP header?
风险在于攻击者最终可能会暴力破解令牌值。
建议每个 session 有一个新的 CSRF 令牌。如果你让它持久化,那么恶意站点可能会继续尝试提交一个跨站点请求,每次都包含不同的令牌值。最终它将尝试令牌字符的每个组合并成功发出请求。
但实际上,用户必须同时且每次都访问恶意网站。记住用户打开的选项卡并每次自动加载的浏览器可能会发生这种情况。
您还可以内置一些暴力破解保护。例如,在使用无效的 CSRF 令牌发出 10 次请求后,您可以中止 session,然后通知用户他们已注销。这将减轻暴力攻击,但是这会将攻击转换为拒绝服务攻击,因为恶意网站将成功注销用户。因此,您应该通过联系用户并告知他们他们正在访问的网站试图破坏他们来跟进此事(您可以检查您的服务器日志以确定 referer
和 origin
headers).
这与这个问题有关CSRF Protection for Refresh Token Cookie in SPA
我想使用推荐的 XSRF-TOKEN
cookie 机制来保护另一个 HttpOnly cookie。对于这种情况,我需要使 XSRF-TOKEN
cookie 持久化,因为它必须在应用程序重新加载后启动时可用。 Angular $http
中的默认实现仅在 session 个 cookie 中查找。
如果我使 cookie 持久化并手动设置 X-XSRF-TOKEN
HTTP header 有什么风险?
如果您选择使用持久性 cookie,您仍然容易受到 CSRF 攻击,因为浏览器会随请求发送这些 cookie
对于 angularjs,以下是我在我的 SPA 应用程序中使用的内容; CSRF 令牌由后端服务器生成,并仅在对 index.html
文件的请求中作为 header 传递。从那时起,angular 被配置为在 header + session cookie 中添加令牌 - 对于每个内部 $http.post/delete/put/...
请求
app.config(['$httpProvider', function ($httpProvider)
{
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
测试一下
使用这个小片段手动测试您的 api:
<!DOCTYPE html>
<html>
<head>
<script>
function csrf(id)
{
document.getElementById("csrf-form-" + id).submit();
}
</script>
</head>
<body>
<form method="POST" action="http://127.0.0.1:8080/api/test" enctype="text/plain" target="_blank" id="csrf-form-1">
<input name='{"protected":false, "ignore_me":"' value='test"}'type='hidden'>
</form>
<button onclick="csrf(1)"}>CSRF!</button>
</body>
</html>
CSRF 攻击在用户登录的不受保护的站点上起作用。考虑使用会话 cookie C(仅此而已)来识别用户会话的站点 S。这意味着浏览器将在每次向 S 发送请求时发送 C。由于会话 cookie 的存在是确认会话所需的全部内容,因此用户将在访问 S 时登录。这很好。正是我们想要的。
除了...
我们假设 S can 是一个可以通过 URL(例如 https://S/email-cash?email=recipient@examplecom
)通过电子邮件发送现金的网站。一个邪恶的网站 E 可以在其页面之一中嵌入 link https://S/email-cash?email=ATTACKER@examplecom
。现在,当用户在登录站点 S 的同时浏览站点 E 并单击此 link 时,他们最终会通过电子邮件向攻击者发送钱款。更糟糕的是,这个 link 可以在 JavaScript 幕后执行,因此用户只需访问站点 E。非常糟糕。
问题的发生是因为每个带有有效会话 ID cookie C 的请求都被视为有效请求。解决方案是要求浏览器发送一些它只能最近从站点 S 获得的 ID。这就是 CSRF 令牌。浏览器无法获取它,除非它由 S 提供,并且 S 只会在它提供页面时提供它,而不是用于跨站点攻击。
现在,如果您开始将 CSRF 令牌存储为持久性 cookie,它会破坏整个目的,因为它成为浏览器可以在跨站点攻击中发送的东西。
What are risks if I make the cookie persistent and manually set the X-XSRF-TOKEN HTTP header?
风险在于攻击者最终可能会暴力破解令牌值。
建议每个 session 有一个新的 CSRF 令牌。如果你让它持久化,那么恶意站点可能会继续尝试提交一个跨站点请求,每次都包含不同的令牌值。最终它将尝试令牌字符的每个组合并成功发出请求。
但实际上,用户必须同时且每次都访问恶意网站。记住用户打开的选项卡并每次自动加载的浏览器可能会发生这种情况。
您还可以内置一些暴力破解保护。例如,在使用无效的 CSRF 令牌发出 10 次请求后,您可以中止 session,然后通知用户他们已注销。这将减轻暴力攻击,但是这会将攻击转换为拒绝服务攻击,因为恶意网站将成功注销用户。因此,您应该通过联系用户并告知他们他们正在访问的网站试图破坏他们来跟进此事(您可以检查您的服务器日志以确定 referer
和 origin
headers).