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

Posted

技术标签:

【中文标题】没有会话或数据库的安全 CSRF 保护?【英文标题】:Secure CSRF protection without sessions or database? 【发布时间】:2015-06-26 08:41:23 【问题描述】:

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

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

我的安全 user_storage only csrf 的想法:

csrf_token= AES(ip+useragent+timestamp+random_data, csrf_aes_site_key)

当 csrf_aes_site_key 在配置文件中硬编码时。 并且在每次登录/注册后,我将解密 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 保护方式吗?

【问题讨论】:

with only form hidden field /& a cookie 这些都是客户端,因此从定义上讲并不安全。 但如果我错了,请纠正我,攻击者无法操纵\查看我的 csrf_token 数据,如果他可以,他不能使用此令牌从不同的 ip 创建请求,并且它会过期5 分钟...,唯一的缺点是同一个用户可以在同一个表单上多次使用同一个令牌,直到过期...它对我来说看起来很安全...客户端存储安全性仅受以下因素影响你保存它的方式,我只使用用户存储作为我的加密安全数据的存储单元,这些数据在我没有注意到的情况下无法被操纵...... 顺便说一句,为什么不只是一个随机数?这里使用加密的目的是什么? 因为数据从来没有保存在服务器上,只保存在客户端,所以我没有数据可以比较随机字符串,无法验证令牌......如果你使用会话最好的方法是在会话中保存一个随机字符串...但是如果您不想为每个页面访问者保存会话文件/数据库记录,这是我的解决方法,仅用于登录/注册表单... 您可以使用 HMAC (en.wikipedia.org/wiki/Hash-based_message_authentication_code) 代替加密。它会更快。 【参考方案1】:

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

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

这会阻止 CSRF,因为只有从真实来源运行的 JavaScript 才能读取 cookie(参见***上的 detailed discussion)。令牌可以是会话 cookie 的 HMAC,这样就避免了在服务器端记住令牌状态的需要。

主要优点是这种方法(与表单字段中带有标记的方法不同)适用于单页、基于 JavaScript 的应用程序,在这种应用程序中,您不会在服务器上生成 HTML,也不能真正将 CSRF 标记嵌入他们的代码。

【讨论】:

您写道:“令牌可以是会话 cookie 的 HMAC”。所以你假设有一个会话cookie。我认为 OP 提出的解决方案的重点是不应该有任何服务器端存储。当会话(带有 cookie)开始时,这意味着状态被保存在服务器端。【参考方案2】:

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

您也可能会遇到问题,具体取决于您存储了多少用户代理(Google Chrome 可以即时更新自身)。

【讨论】:

【参考方案3】:

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

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

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

步骤 3 到 6 很容易在 5 分钟内完成。

【讨论】:

以上是关于没有会话或数据库的安全 CSRF 保护?的主要内容,如果未能解决你的问题,请参考以下文章

已经实施 csrf 保护时使用会话 id 的目的是啥?

Spring 安全中的条件 CSRF 保护

使用会话令牌或随机数进行跨站点请求伪造保护 (CSRF)?

对 CSRF 保护策略感到困惑

使用会话令牌实现 CSRF 保护

是否有必要保护 JAX-RS 请求免受 CSRF 影响?