我的无会话身份验证系统安全吗?

信息安全 验证 哈希 http 饼干
2021-08-14 02:32:27

所以,我创建了一个身份验证系统。为任何类型的安全漏洞倾注了它并测试了它的废话。我认为它相当安全,但它有一个“不同”的设计方面,这在 Web 身份验证系统中并不常见。

基本上,我想做到这一点,这样就可以在不跟踪每个用户会话的情况下完成身份验证。这意味着数据库上的负载更少,扩展和缓存也很简单。以下是服务器保存的“秘密”:

  • 私钥保存在应用程序的源代码中
  • 为每个用户保留一个随机生成的盐

为了使其无会话,但不容易伪造cookie,这是我的cookie的格式

expires=expiretimestamp
secret=hash(privatekey + otherinfo + username + hashedpassword + expires)
username=username

otherinfo例如 IP 地址、浏览器信息等,以及hashedpassword=hash(username + salt + password + privatekey)

我的理解是伪造登录cookie(不破解密码)需要:

  1. 对应用程序的源代码访问,或一种诱骗它吐出私钥的方法
  2. 对数据库进行只读访问以获取 salt 和 hashedpassword

而传统的会话方法需要:

  1. 对数据库的写入和读取访问(注入会话,或欺骗 Web 应用程序为您执行此操作)
  2. 可能访问源代码,具体取决于它的工作方式

无论如何,这对任何人来说似乎都过于不安全了吗?我有什么方法可以改进它并使其更安全(同时保持无状态/无会话模型)?是否有任何现有的身份验证系统使用这种无状态模型?

此外,哈希方法基本上可以是任何东西,从 SHA256 到 Blowfish

3个回答

您的基本概念并不新鲜:您希望有一些与用户关联的状态,但您不想自己存储该状态。相反,您将其存储在客户端(在 cookie 中)。由于您想防止这种状态的更改(例如,客户端从头开始构建 cookie),因此您需要进行完整性检查,例如Message Authentication Code您使用散列函数的构造是粗略的 MAC。由于长度扩展攻击,它恰好是具有通常散列函数的弱 MAC

如果您想要 MAC,请使用强大的 MAC,这意味着HMAC它是标准的和广泛的。

当然,密钥的存储(用于 MAC 计算)是一个棘手的问题。嵌入在应用程序“源代码”中的东西作为文件存在,应用程序(本质上)可以读取该文件,使其容易受到获取对任意文件的非法读取访问权限的攻击。最好(但更难)安排应用程序通过某种本地通信协议动态获取 MAC 密钥(应用程序联系本地服务器,该服务器仅将密钥提供给应用程序);这样,密钥将仅存在于应用程序的 RAM 中,而不是作为具有应用程序访问权限的文件可读。这不是绝对的保护(如果你的服务器被彻底黑了,好吧,就是这样),但在实践中它会更强大。

我看到您在经过 MAC 处理的数据中包含了散列密码。这有点奇怪;您已经拥有 MAC 作为认证:MAC 证明 cookie 数据是真实的,因此无需进一步认证。

Blowfish 不是哈希函数;它是一种分组密码(或一种),因此不能用于散列,除非对其进行大量修改,这意味着自制密码学,这不是一个好主意。


如果您正在卸载客户端上的状态,您可能想要卸载客户端自己不应该知道的状态。这意味着您可能还需要加密。安全地结合加密和 MAC 并不像看起来那么容易;有一些模式我推荐EAX


请注意,不保持状态会使您天生对重放攻击很弱。这是不可避免的。您可以通过使用较短的有效期(例如 cookie 在 15 分钟内过期)将损失降到最低。

这个提议的系统是一个会话处理程序,用于维护经过身份验证的状态,并且您构建会话令牌的方法是不安全的。

例如,使用 SQL 注入,您可以从数据库中读取大部分机密数据。如果您使用 MySQL SQL 注入,则可以使用 load_file() 函数读取文件,该函数可用于从配置文件中读取密钥。

一般来说,您不应该在构建系统时重新发明轮子。我确信您的平台带有一个安全的会话处理程序,因为几乎每个 Web 应用程序都需要一个。

会话 ID 应该是纯随机值,像 /dev/urandom 这样的熵池是一个很好的选择。仅仅因为您正在使用平台的会话处理程序并不意味着它的配置正确。我建议阅读OWASP 会话管理备忘单

为了使其无会话,但不容易伪造cookie,这是我的cookie的格式

您所描述的不是无会话的-只是身份验证状态保存在浏览器而不是服务器上。

即使对于仅 SSL 的站点,尝试检测会话劫持和固定也是一个好主意(对于固定,可用的漏洞利用类型受到更多限制,因为推测身份验证直接与会话管理相关联),这意味着存储数据服务器端。

未经授权,身份验证不是很有用(请不要告诉我您的授权直接内置在您的代码中),这又取决于服务器端保存的信息。

您仍然需要重新生成哈希以验证每个请求或将哈希存储在查找表中 - 这意味着在服务器上检索数据。

然后,如果您有任何类型的数据处理,那么除了事务性数据之外,您还应该有 CSRF 预防——这通常是通过在服务器端存储数据来实现的。

与使用传统的 Web 会话相比,我看不出您是如何减少工作量的。如果您只是简单地包含了用户名、过期时间以及用户名和过期时间的哈希值,那么是的,可以依赖 cookie 值来提供与传统 Web 会话相同的身份证明 - 但这仅允许非常有限授权/访问模型。