我的 CSRF 保护方法安全吗?
Posted
技术标签:
【中文标题】我的 CSRF 保护方法安全吗?【英文标题】:Is my CSRF protection method secure? 【发布时间】:2018-03-09 00:44:11 【问题描述】:我一直在使用 php 进行自己的 CSRF 保护。根据我所读到的内容,我决定使用 cookie 来实现我的保护,但对于我的方法是否能够抵御 CSRF 攻击感到有点困惑。
所以我的方法如下:
用户发送登录请求
服务器检查是否设置了 CSRF 令牌,如果未设置,则创建一个并将其存储在其 Session 中并使用该令牌创建一个 Cookie
通过检查是否在 POST 请求中来验证 CSRF 令牌,如果不在则检查 $_COOKIE 中的令牌
如果令牌无效则发回消息...
我决定使用 cookie 来存储令牌,因为这适用于 Ajax 请求,而且我不必在每次使用 Ajax POST 时都包含它。
我感到困惑的是攻击者不能只是提出请求吗? POST 或 GET,因为 cookie 在那里,它只是随请求一起发送,因此是一个有效的请求,因为令牌每次都与浏览器一起发送?
【问题讨论】:
CodeReview 会更适合你,我相信。 浏览器将阻止跨站点请求,因此任何在 cookie 中具有有效 CSRF 令牌的请求通常来自浏览您自己的域的客户端(除非您在某些路由中启用了 CORS,在这种情况下您需要小心)。 ***.com/a/20518324/487813 是一本很好的读物 @apokryfos no ,浏览器一般不会阻止跨站请求。它们会阻止您希望取回数据的请求。XMLHttpRequest
使用 CORS。但是使用 javascript 提交的隐藏 <form>
仍然可以向外部域发送 POST 请求。并且此类请求将包括用户的所有 cookie。将 CSRF 存储在 Cookie 中就像没有 CSRF 令牌一样。
@apokryfos 涵盖此内容的相关部分是 [...]Simple cross-origin requests generated outside this specification (such as cross-origin form submissions using GET or POST or cross-origin GET requests resulting from script elements) typically include user credentials, so resources conforming to this specification must always be prepared to expect simple cross-origin requests with credentials.[...]
(4 Security Considerations)
【参考方案1】:
cookie 不应包含 CSRF 令牌。只有客户端会话存储应该包含它。而且你不应该反对 cookie 中的 CSRF。
如果您检查与 cookie 一起发送的 CSRF,您将绕过 CSRF 背后的想法。
一个简单的攻击场景是外国网站上的隐藏表单:
<form method="method" action="http://site-to-gain-access-to.tld/someactionurl">
<!-- some form data -->
</form>
并且这个隐藏的表单将在没有用户干预的情况下使用 javascript 执行。如果用户在site-to-gain-access-to.tld
站点上登录并且如果没有激活 CSRF 保护,那么就像用户本身会触发该操作一样,因为用户的会话 cookie 将与该请求一起发送。因此服务器会假设是用户触发了该请求。
如果您现在将 CSRF 令牌放入您的 cookie 中,您将遇到与会话相同的问题。
CSRF 令牌必须始终仅作为请求正文或 url 的一部分发送,而不是作为 cookie。
所以突出显示的部分:
服务器检查是否设置了 CSRF 令牌,如果没有则创建一个并将其存储在他们的 Session 中并创建一个 带有令牌的 Cookie
通过检查是否在 POST 请求中来验证 CSRF 令牌,如果不在则检查 $_COOKIE 中的令牌
会破坏 CSRF 保护。 CSRF 是作为明文存储在 cookie 中还是以服务器端加密的形式存储并不重要。
【讨论】:
对,好吧,我想这对我来说很清楚。如果我是正确的,那么仅将 CSRF 令牌作为隐藏输入包含在我要发送的表单中,然后将其与服务器上会话中的令牌进行比较就足以防止 CSRF 攻击? 是的,您应该只将其作为隐藏输入包含在表单中,并将其与服务器端会话存储进行比较。这是使您的网站安全的一部分。您肯定需要确保您的站点再次保存 XSS 攻击,否则恶意脚本可能能够访问该 CSRF 令牌。所以 session id 确认请求是由用户的浏览器完成的,CSRF 确认请求是由用户完成的。 好吧,这是有道理的。但是对于 Ajax 请求,包含位于页面上 div 中的 CSRF 令牌是否仍然安全,因为我的一些 Ajax 请求不是来自正在发布的表单? @Erdss4 是的,您可以将 CSRF 令牌与 ajax 请求一起传递,作为请求正文中的属性,或作为带有x-
标头的标头,例如 X-CSRF-Token
。个人会使用 x-
标头,因为它不会干扰您的请求数据。
@Erdss4 您将 data attribute 添加到 html 元素 (Using data attributes)。这些可以在现代浏览器中使用nodeElement.dataset
直接访问,也可以在库中访问,例如:jQuery.data()【参考方案2】:
只要“用户发送登录请求”是指登录页面的初始GET请求,这是正确的。 CSRF 应该在 GET 请求中生成和存储,并在每次 POST 期间进行验证。
我感到困惑的是攻击者不能只是提出请求吗? POST 或 GET,因为 cookie 在那里,它只是随请求一起发送,因此是一个有效的请求,因为令牌每次都与浏览器一起发送?
是的。 CSRF 令牌不是秘密的。他们只是确认只有在发出预期的 GET 请求后才发出 POST。这意味着某人只有在他们首先请求表单时才能提交表单。它可以防止不良站点通过 POST 将用户发送到您的站点。它不会阻止攻击者发出 GET 请求、获取令牌和发出有效的 POST。
来自OWASP:
借助一些社会工程学的帮助(例如通过电子邮件或聊天发送链接),攻击者可能会诱骗 Web 应用程序的用户执行攻击者选择的操作。如果受害者是普通用户,成功的 CSRF 攻击可以强制用户执行状态更改请求。
【讨论】:
因此,如果我只是将我的令牌作为隐藏输入包含在每个表单中,并使用存储在 SESSION 变量中的令牌来验证令牌,这还不够吗?您是说令牌也应该是表单操作中 GET 请求的一部分吗? 在隐藏的输入元素中包含标记就足够了(只要您的站点不更改 GET 请求的数据)。我在解释令牌是在 GET 请求期间生成的(用表单检索页面)。您可以使用 cookie 或隐藏的输入元素,然后通过 POST 再次提交令牌。 那么您是否可以忽略在表单中放置隐藏的输入,而只依赖每次发送的 cookie? Cookie 需要一些额外的注意事项。我看到它们列在其他人的 cmets 和帖子中。还可以从我提供的 OWASP 链接中阅读相关页面。以上是关于我的 CSRF 保护方法安全吗?的主要内容,如果未能解决你的问题,请参考以下文章