揭秘 Web 身份验证(无状态会话 Cookie)

信息安全 密码 验证 饼干 会话管理
2021-09-02 17:30:17

我目前正在研究我正在开发的网站的用户身份验证协议。我想创建一个身份验证 cookie,以便用户可以在页面之间保持登录状态。

这是我的第一个 bash:

cookie = user_id|expiry_date|HMAC(user_id|expiry_date, k)

其中kHMAC(user_id|expiry_date, sk)sk只有服务器知道的 256 位密钥。HMAC 是一个 SHA-256 哈希。请注意,“|” 是一个分隔符,而不仅仅是串联。

这在 PHP 中看起来像这样(注意,这个问题与语言无关,PHP 只是一个示例):

$key = hash_hmac('sha256', $user_id . '|' . $expiry_time, SECRET_KEY);
$digest = hash_hmac('sha256', $user_id . '|' . $expiry_time, $key);
$cookie = $user_id . '|' . $expiry_time . '|' . $digest;

我可以看到它很容易受到A Secure Cookie Protocol中所述的重放攻击,但应该能够抵抗卷攻击和加密拼接。

问题: 我在这里是正确的,还是我错过了一个巨大的漏洞?有没有办法防御使用动态分配的 IP 地址且不使用会话的重放攻击?我不想在服务器端存储任何东西来完成这项工作。

另外,我没有计划或滚动我自己的。我问这个是为了更好地判断我应该选择什么解决方案。因此,没有某种解释就没有“仅使用 X 解决方案”的答案。

笔记

我读过的最新材料:
Web 上客户端身份验证的注意事项, 又名 Fu 等。
https://pdos.csail.mit.edu/papers/webauth:sec10.pdf

安全 Cookie 协议 ,又名 Liu 等人。
( http://www.cse.msu.edu/~alexliu/publications/Cookie/cookie.pdf )
扩展了前一种方法

强化无状态会话 Cookie
( http://www.lightbluetouchpaper.org/2008/05/16/hardened-stateless-session-cookies/ )
,它也扩展了之前的方法。

由于这个主题非常复杂,我只是在寻找具有创建和破坏身份验证方案的实际经验的安全专家的答案。

4个回答

“重放攻击”并不真正适用于 cookie,因为 cookie根据定义是要被重放的东西:用户的浏览器发回相同的 cookie 值,这就是您的服务器知道它是同一个用户的方式。

您要避免的是有人监视在线,观察 cookie 值,然后在他自己的连接上发送相同的 cookie。唯一已知的实用解决方案是在隧道内运行整个协议,以确保传输中数据的机密性和完整性,这就是所谓的“SSL”(又名HTTPS)。

然后有两种方法可以在服务器上生成和验证 cookie 值:

  • 您可以只生成一个足够大的随机值(即 16 字节左右),这样攻击者就不太可能仅仅靠运气猜测该值。服务器为每个用户记住他当前的“会话令牌”,作为“用户”数据库中的一个额外列。

  • 您将令牌生成为根据用户标识符确定性计算的不可伪造值。这就是你所做的,这是一个合理的概念。基本上,不是在服务器上存储一些额外的状态,而是在客户端上卸载它,并且使用带有服务器端密钥的MAC,这样客户端就不能伪造“有效”的 cookie 值。

您的代码描述了两个嵌套的 HMAC 调用,这很奇怪且没有根据。一个电话就足够了。通用结构是一个 cookie 包含一个值v和一个 MAC m以便v编码您想要存储在客户端中的状态,并且m是在v上计算的在您的情况下,您要存储的状态是:“此客户端具有用户 ID i并在时间t登录”。你可以使用任何你想要的编码,只要你能明确地解码它。

总结一下:使用 MAC 生成 cookie 值是一种有效的会话管理方式,而 HMAC/SHA-256 对此很有用。但是您必须将其视为一种优化:您将值存储在客户端中以避免将它们存储在服务器上。这会带来不幸的后果,即客户端可能会忘记您无法控制的数据(客户端可能会破坏 cookie)或进行时间扭曲(客户端可能会将其浏览器中存储的值更改为较旧的 cookie 值——这个问题是在 MAC 的控制下,通过在 cookie 中包含日期来缓解)。

如果您可以保留状态服务器端并且只使用随机 cookie 值,那么就这样做:它更简单,并且为服务器提供了更多控制权。

保护任何 Web 应用程序的第一步是使用 SSL。这可以使您的 cookie 保密,防止重放攻击,确保用户与正确的服务器交谈,防止中间人,防止攻击者更改网络上的数据......

然后secure在 cookie 上设置标志,所以它只通过 SSL 发送。设置http-only标志,以防止 javascript 读取它也不会受到伤害。

最后关于您的 cookie 方案:

  • 嵌套的 HMAC 不会为您带来任何好处。一起去吧user_id|expiry_date|HMAC(user_id|expiry_date, SECRET_KEY)
  • SECRET_KEY定期更换
  • user_id绝不能改变即使用数字 user_id,而不是用户名或电子邮件
  • 既不user_id也不expiry_date应该包含 a|以确保干净的域分离
  • 如果您是偏执狂,请使用专门的登录服务器,对 cookie 进行签名而不是 MAC 化。所以登录服务器是唯一拥有创建 cookie 所需密钥的服务器,普通网络服务器只能验证它。=> 减少攻击面
  • 服务器可以为任何用户创建有效的 cookie。这可能是不可取的。

首先也是最重要的:

不要发明自己的安全协议。你很可能会弄错。

现在已经不碍事了,让我们看看这个。如果我能够在HMAC(userid|expiry_date, k)没有登录或以该用户身份进行身份验证的情况下获得 ,我已经破坏了该系统的安全性。这延伸到各种问题,例如会话固定或会话劫持攻击(通常是由于未使用 SSL/TLS 或不正确使用 SSL/TLS 导致的)。

当您检查会话 cookie 时,您是否从定时侧通道泄漏信息?您确定正确使用 HMAC 吗?您说您的 HMACSHA-256,您实际上是指 HMAC-SHA-256 吗?当您可以生成一个随机字符串并将其与服务器上的用户(例如在数据库中)相关联时,为什么还要经历一个复杂的 HMAC 过程?为什么不直接使用user_id|expiry_date|HMAC-SHA-256(user_id|expiry_date, sk)|连接在哪里,而不是文字管道字符)?

至于在基于 Web 的环境中防御重放攻击,请查看OWASP 的 CSRFGuard 项目您将无法直接集成它,但在某处可能有一个 PHP 等价物。但是,如果您的网站容易受到 XSS 攻击,这一切都没有实际意义。

安全性应该交给一个受人尊敬、久经考验的框架,而不是临时完成

编辑,关于会话固定攻击的简短说明:

我假设如果您没有将安全性交给经过良好测试的框架,那么您可能很容易受到攻击。当用户进行身份验证时,您必须基本上检查您是否发出了不同的会话密钥(即与用户开始使用的不同)。使用上述策略,user_id|expiry_date|HMAC(user_id|expiry_date, k)当用户进行身份验证时不会更改,从而使他们容易受到会话固定攻击。

由于这个主题非常复杂,我只是在寻找具有创建和破坏身份验证方案的实际经验的安全专家的答案。

你说得对,这个主题非常复杂。

使用框架提供的会话功能,不要尝试自己动手。如果您使用的是普通 PHP 而不是框架...不寒而栗