我试图学习如何使用CSRF令牌来保护我的表单,而且从我所读过的内容来看,我认为我所做的是安全的,但我对此并不了解真正验证该陈述。
到目前为止,我正在做的是以下步骤:
使用openssl_random_pseudo_bytes();
生成密钥,然后将该密钥存储在会话中。首次创建会话时会生成此密钥。
在每个页面上使用密钥加密会话ID以生成CSRF令牌,使用:
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), session_id(), MCRYPT_MODE_CBC, md5(md5($key))));
将CSRF令牌放入表单中的隐藏输入中。
在页面加载检查发布,如果发布,解密CSRF令牌并使用
与Session_id进行比较$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
如果解密的令牌与会话ID匹配,则继续使用表单,否则,请将用户注销并重定向到主页。
到目前为止,我的问题如下:
攻击者是否有可能劫持会话并获取密钥?如果是这样,这会影响支票的完整性,因为他们不知道我用所述密钥加密了什么?
我知道到目前为止,没有任何东西容易受到XSS的攻击(据我所知),攻击者是否有可能从合法用户那里获取CSRF令牌?
设置方式,CSRF令牌是每个会话仅生成一次,即使会话和令牌在几小时后超时,这似乎也不是很安全。是否应在每次页面加载时生成令牌?如果是这样,那么使用多个标签的用户不会感到困扰吗?
感谢任何帮助,我仍然在努力学习这一切,安全性比我最初想象的要复杂得多。
答案 0 :(得分:2)
如果您的应用上有XSS,攻击者可以窃取会话。但偷密钥看起来更难,因为它从未暴露在前端。
可能存在其他漏洞可能导致令牌不正确的通信等劫持行为。令牌总是被盗。
作为改进,可以为每个表单再次生成CSRF令牌。在这种情况下,应该按用户会话存储生成的有效CSRF令牌列表。因此,在给定时刻,用户可能存在多个有效的CSRF令牌。这将允许用户处理多个选项卡。
您可能需要阅读OWASP Session Management Recommendations。它有点长但很有帮助。
我认为为每个页面创建一个新的CSRF令牌有点太多"安全"相比它的好处。实际上OWASP CSRF Prevention Cheat Sheet描述了每个会话使用单个令牌进行预防。
使用单向散列(如sha-512)创建令牌而不是加密会话ID会更安全。