我一直在使用PHP进行自己的CSRF保护。根据我的阅读,我决定使用cookie来实现我的保护,但是对于我的方法是否可以抵御CSRF攻击感到有些困惑。
所以我的方法如下:
用户发送登录请求
服务器检查是否设置了CSRF令牌,如果没有设置,则将其存储在会话中并使用令牌创建Cookie
通过检查是否在POST请求中验证CSRF令牌,如果没有,则在$ _COOKIE中检查令牌
如果令牌无效,则发回消息......
我决定使用cookie来存储令牌,因为这将适用于Ajax请求,每次使用Ajax POST时我都不必包含它。
我感到困惑的是攻击者不能提出请求; POST或GET,因为cookie就在那里,无论如何它都会随请求一起发送,因此每次都会随浏览器一起发送令牌,这是一个有效的请求?
答案 0 :(得分:4)
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令牌必须始终仅作为请求正文或网址的一部分发送,而不是作为Cookie发送。
所以突出显示的部分:
服务器检查是否设置了CSRF令牌,如果没有设置,则将其存储在会话中并使用令牌创建 Cookie
通过检查是否在POST请求中验证CSRF令牌,如果没有,则检查$ _COOKIE中的令牌
会打破CSRF保护。 CSRF是以明文还是服务器端加密存储在cookie中无关紧要。
答案 1 :(得分:1)
只要“用户发送登录请求”是指登录页面的初始GET请求,这是正确的。应该生成CSRF并将其存储在GET请求中,并在每次POST期间进行验证。
我感到困惑的是攻击者不能提出请求; POST或GET,因为cookie就在那里,无论如何它都会随请求一起发送,因此每次都会随浏览器一起发送令牌,这是一个有效的请求?
是。 CSRF代币并不是秘密。他们只是确认在发出预期的GET请求后才进行POST。这意味着,如果他们首先要求提供表格,则他们只能提交表格。它可以防止恶意网站通过POST将用户发送到您的网站。它不会阻止攻击者发出GET请求,获取令牌以及进行有效的POST。
来自OWASP:
在社交工程的帮助下(例如通过电子邮件或聊天发送链接),攻击者可能会欺骗Web应用程序的用户执行攻击者选择的操作。如果受害者是普通用户,则成功的CSRF攻击可以强制用户执行状态更改请求。