没有会话或数据库的安全 CSRF 保护?

Secure CSRF protection without sessions or database?

我正在尝试对 HTML 登录表单实施安全的 CSRF 保护, 我知道实现 CSRF 保护的最佳方法是在会话中随机存储 csrf_key, 但我想将 CSRF 添加到我的登录和注册表格中...我不想为任何匿名未注册用户存储许多会话...

所以我想在不使用会话或数据库的情况下创建最好的安全方案,仅使用表单隐藏字段/& cookie,登录后我将使用会话 csrf 保护。

我的安全想法 user_storage 只有 csrf:

csrf_token= AES(ip+用户代理+时间戳+random_data, csrf_aes_site_key)

当 csrf_aes_site_key 硬编码在配置文件中时。 在每个 login/register 之后,我将解密 AES 字符串 + 验证 ip&ua 与请求 ip&ua 匹配,并且时间戳不太匹配,假设 5 分钟(如果 csrf_timestamp + 18000>=current_ts), 并且 random_data 只是随机性 (并确保同一用户在同一 ts 中多次请求时不会得到相同的 csrf_token)...

所以...它是否足够安全,是不是一个好的解决方案? 如果没有,还有其他解决这个难题的建议吗? 谢谢!

编辑: 我刚刚创建的实现,它运行良好,但它是否足够好?

完整示例: https://github.com/itaiarbel/aes_based_csrf_protection

问题 1: 用户可以使用 csrf_token 并在接下来的 5 分钟内使用相同的令牌成功提交表单 漏洞?如果用户多次提交,我在乎什么?只要不是csrf攻击...

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

您能发现此实施的任何特定安全风险吗?或者我可以假设这是进行 CSRF 保护的安全方法吗?

将 CSRF 令牌存储在 cookie 中的方法被广泛使用 (AngularJS, Django),但它的工作方式有点不同。服务器在cookie中发送令牌,客户端使用JavaScript读取cookie并反射令牌在HTTP header。服务器应该只验证来自 HTTP header 的值,即使 cookie 也会自动发送。

实际的 cookie 和 header 名称并不重要,只要 JavaScript 前端和后端都知道它们。

这可以防止 CSRF,因为只有来自真实来源的 JavaScript 运行 才能读取 cookie(请参阅维基百科上的 detailed discussion)。令牌可以是 session cookie 的 HMAC,这样就无需在服务器端记住令牌状态。

主要优点是这种方法(与在表单字段中使用令牌的方法不同)适用于基于 single-page、JavaScript 的应用程序,您不会在其中生成 HTML服务器并不能真正将 CSRF 令牌嵌入到他们的代码中。

它适用于大多数客户端 - 但在客户端通过负载平衡代理(您看到的客户端 IP 发生变化)访问您的站点时会严重失败。更正确的解决方案是使用来自 whois 记录或 ASN 编号的组织数据,但查找这些数据会产生费用——具体取决于流量,仅使用 (IPV4) 地址的前 16 位可能就足够了。

您也可能 运行 遇到问题,具体取决于您存储了多少用户代理(Google Chrome 可以动态更新)。

我看起来很没有安全感。不要使用这个。登录表单和注册表单需要全面的 CSRF 保护;使用任何类型的降低保护都是不可接受的。

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

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

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