因此,我创建了一个以所有形式自动插入的类:<input type="hidden" name="csrf" value="csrf_value_uniq_id" />
现在我的问题是,我将密钥设置为在 5 分钟后过期,但是如果您停留在页面上,或者您回来后去吃饭并提交表单,则 csrf 密钥将不匹配。
现在,我可以将其设置为在 24 小时内到期,但我不知道这是否会像预期的那样安全。我在邮寄表格上使用它。
那么最好的解决方案是什么我应该怎么做呢?
因此,我创建了一个以所有形式自动插入的类:<input type="hidden" name="csrf" value="csrf_value_uniq_id" />
现在我的问题是,我将密钥设置为在 5 分钟后过期,但是如果您停留在页面上,或者您回来后去吃饭并提交表单,则 csrf 密钥将不匹配。
现在,我可以将其设置为在 24 小时内到期,但我不知道这是否会像预期的那样安全。我在邮寄表格上使用它。
那么最好的解决方案是什么我应该怎么做呢?
不需要服务器端状态并因此超时的解决方案是签名令牌。您创建一个包含在表单中的随机值,然后使用只有您知道的秘密签署该令牌:
$secret = 'weufiwu93tu2b248hg24';
$token = uniqid('', true);
$signature = sha1($secret . ':' . $token);
然后,您将令牌和签名嵌入到表单中。再次收到表单后,您使用SHA1(secret:token)
表单中的令牌重复操作,并将结果与表单中的签名进行比较。如果你有一个精心挑选的随机秘密和一个健壮的散列,那么除了知道秘密的人之外,没有人能够签署令牌,因此你已经证明令牌来自你。
此外,您可以在表单/签名中包含时间戳以限制令牌的有效性(使其超过 5 分钟,但不足以使令牌永远可用),用户 id 将令牌绑定到特定用户,防止表单字段注入的预期表单字段以及您可能想要检查的任何其他内容。例如:
signature = SHA1(secret:token:timestamp:userid:[form_field_name[:...]])
对于上述签名,您在表单中嵌入了签名、令牌、时间戳和显然的表单字段;提交后,您检查提交的时间戳是否在某个窗口内,从服务器获取秘密和用户 ID,使用所有这些部分重新创建签名,并根据提交的签名进行检查。
请注意,上面的代码只是一个示例,您的令牌应该使用更好的随机性来源并且更长,并且您的散列函数应该是更健壮的东西,例如 HMAC 或 bcrypt。这里是为了传达想法,而不是实现细节。
可以在此处找到实际实现:Kunststube\CSRFP。我把它放在一起来回答这个问题,因为无论如何我都需要类似的东西。
攻击者可以通过两种可能的方式获取有效令牌:
前者可以通过使用具有足够熵的适当随机源来缓解。后者可以通过保护传输(即 HTTPS)和防止攻击(如可用于获取用户令牌的跨站点脚本)来建立。
如果你两者都做,你甚至可以让它永不过期(或在用户会话结束时)。