在会话中存储CSRF的密钥?

时间:2014-03-17 16:11:36

标签: php session encryption csrf

我试图学习如何使用CSRF令牌来保护我的表单,而且从我所读过的内容来看,我认为我所做的是安全的,但我对此并不了解真正验证该陈述。

到目前为止,我正在做的是以下步骤:

  1. 使用openssl_random_pseudo_bytes();生成密钥,然后将该密钥存储在会话中。首次创建会话时会生成此密钥。

  2. 在每个页面上使用密钥加密会话ID以生成CSRF令牌,使用:

    $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), session_id(), MCRYPT_MODE_CBC, md5(md5($key))));
    
  3. 将CSRF令牌放入表单中的隐藏输入中。

  4. 在页面加载检查发布,如果发布,解密CSRF令牌并使用

    与Session_id进行比较
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
    
  5. 如果解密的令牌与会话ID匹配,则继续使用表单,否则,请将用户注销并重定向到主页。

  6. 到目前为止,我的问题如下:

    1. 攻击者是否有可能劫持会话并获取密钥?如果是这样,这会影响支票的完整性,因为他们不知道我用所述密钥加密了什么?

    2. 我知道到目前为止,没有任何东西容易受到XSS的攻击(据我所知),攻击者是否有可能从合法用户那里获取CSRF令牌?

    3. 设置方式,CSRF令牌是每个会话仅生成一次,即使会话和令牌在几小时后超时,这似乎也不是很安全。是否应在每次页面加载时生成令牌?如果是这样,那么使用多个标签的用户不会感到困扰吗?

    4. 感谢任何帮助,我仍然在努力学习这一切,安全性比我最初想象的要复杂得多。

1 个答案:

答案 0 :(得分:2)

  1. 如果您的应用上有XSS,攻击者可以窃取会话。但偷密钥看起来更难,因为它从未暴露在前端。

  2. 可能存在其他漏洞可能导致令牌不正确的通信等劫持行为。令牌总是被盗。

  3. 作为改进,可以为每个表单再次生成CSRF令牌。在这种情况下,应该按用户会话存储生成的有效CSRF令牌列表。因此,在给定时刻,用户可能存在多个有效的CSRF令牌。这将允许用户处理多个选项卡。

  4. 您可能需要阅读OWASP Session Management Recommendations。它有点长但很有帮助。

    我认为为每个页面创建一个新的CSRF令牌有点太多"安全"相比它的好处。实际上OWASP CSRF Prevention Cheat Sheet描述了每个会话使用单个令牌进行预防。

    使用单向散列(如sha-512)创建令牌而不是加密会话ID会更安全。