没有使用会话或数据库如何实现安全的CSRF保护?

6
我正在尝试为HTML登录表单实现安全的CSRF保护,我知道实现CSRF保护的最佳方法是在会话中存储随机csrf_key,但我想将CSRF添加到我的登录和注册表单中...并且不想为任何匿名未注册用户存储多个会话...
因此,我希望创建最安全的解决方案,而不使用会话或数据库,只使用表单隐藏字段/和一个cookie,在登录后我将使用会话csrf保护。
我的安全用户存储仅CSRF的想法:
csrf_token = AES(ip + useragent + timestamp + random_data,csrf_aes_site_key)
其中csrf_aes_site_key在配置文件中硬编码。每次登录/注册后,我将解密AES字符串并验证ip和ua是否与请求ip和ua匹配,timestamp是否不超过5分钟(如果csrf_timestamp + 18000> = current_ts),random_data就是随机性(并确保同一用户在同一ts中多次请求不会获得相同的csrf_token)...
那么...它足够安全吗?这是一个好的解决方案吗? 如果不是,有没有其他建议来解决这个问题? 谢谢!

编辑: 我刚刚创建了一个实现,它工作得很好,但是否足够好呢?

完整的例子: https://github.com/itaiarbel/aes_based_csrf_protection

问题 1: 用户可能会获取 csrf_token 并在接下来的 5 分钟内成功提交表单,使用相同的令牌。 这是个 bug 吗?我关心用户提交多少次并不重要,只要不是 csrf 攻击...

问题 2: 如果页面保持打开状态 5 分钟,用户将无法登录, (每 5 分钟自动刷新登录页面?也许将其更改为 1 小时?)

您能发现此实现中的任何特定安全风险吗?或者我可以认为这是一种安全的 CSRF 保护方式吗?


只使用表单隐藏字段和 cookie,这两者都是客户端的,因此从定义上来说不安全。 - jeroen
但是请纠正我,攻击者无法操纵/查看我的csrf_token数据,即使他可以,他也无法使用此令牌从不同的IP创建请求,并且它在5分钟内过期...唯一的缺点是相同的令牌可以由同一用户在同一表单上多次使用,直到过期... 在我看来,这看起来非常安全...客户端存储安全性仅受您保存方式的影响,我只将用户存储用作我的加密安全数据的存储单元,该数据无法在没有我注意到的情况下被操纵... - itai
1
你可以使用HMAC(https://en.wikipedia.org/wiki/Hash-based_message_authentication_code)代替加密。这样会更快。 - Neil Smithline
如果您只使用一台服务器(例如:非分布式),那么您是否可以将CSRF随机数存储在内存数据结构中?您可以在几分钟后将它们超时。 - Neil Smithline
这可以与您想要的许多服务器一起使用(假设所有服务器都共享相同的时区),但我开始认为这是过度杀伤力了...将cookie_value的随机字符串与hidden_field_value进行比较对于登录/注册表单已经足够好了... - itai
显示剩余6条评论
3个回答

8
使用cookie存储CSRF令牌的方法非常普遍(AngularJSDjango),但它的工作方式有些不同。服务器在cookie中发送令牌,客户端使用JavaScript读取cookie并在HTTP头反映令牌。服务器应该仅验证来自HTTP头的值,尽管cookie也将自动发送。
实际的cookie和header名称并不重要,只要JavaScript前端和后端都知道它们即可。
这可以防止CSRF攻击,因为只有来自真正来源的JavaScript才能读取cookie(请参见维基百科上的详细讨论)。令牌可以是会话cookie的HMAC,这避免了在服务器端记住令牌状态的需要。
主要优点是这种方法(与表单字段中的方法不同)适用于单页、基于JavaScript的应用程序,在这些应用程序中,您无法在服务器上生成HTML,也无法在其代码中嵌入CSRF令牌。

1
你写道:“令牌可以是会话cookie的HMAC”。因此,您假设存在会话cookie。我认为OP提出的解决方案的整个重点在于根本不应该有任何服务器端存储。当启动会话(带有cookie)时,这意味着状态正在服务器端保持。 - zmippie

0

它适用于大多数客户端,但在客户端通过负载平衡代理访问您的站点时会失败(您看到的客户端IP将更改)。更正确的解决方案是使用whois记录或ASN号码中的组织数据,但查找这些数据需要费用 - 根据流量量,仅使用(IPV4)地址的前16位可能已足够。

根据您存储的用户代理的数量,您还可能会遇到问题(Google Chrome可以实时更新自身)。


0

看起来对我来说非常不安全。不要使用这个。登录表单和注册表单需要完整的CSRF保护;使用任何形式的减少保护都是不可接受的。

您的设置似乎很容易受到同一NAT后面的任何人(因此共享IP地址)的攻击,这在人们的家庭甚至许多工作场所中非常普遍。以下是一个示例场景:

  1. 恶意同事(MC)在网站上注册了一个新帐户
  2. MC找出受害者的用户代理,这很容易做到
  3. MC在发送受害者的用户代理的同时从网站获取CSRF令牌
  4. MC制作了一个恶意网站,其中包含:
    • 一个隐藏的登录表单,在加载时自动提交
    • 上述CSRF令牌
    • 一个有趣的猫咪模因
  5. MC向受害者发送链接,说“哈哈,看看这个”
  6. 受害者欣赏了这个模因,但现在已经在不知情的情况下登录到网站上
  7. MC说服受害者开始使用该网站,生成有关已登录帐户的数据或元数据
  8. MC可以查看所有这些数据,因为他们可以访问相同的帐户

步骤3到6可以在5分钟内轻松完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接