生成 OAuth 令牌的最佳实践?

Posted

技术标签:

【中文标题】生成 OAuth 令牌的最佳实践?【英文标题】:Best practices around generating OAuth tokens? 【发布时间】:2010-12-10 05:45:40 【问题描述】:

我意识到OAuth spec 没有指定有关 ConsumerKey、ConsumerSecret、AccessToken、RequestToken、TokenSecret 或验证程序代码来源的任何信息,但我很好奇是否有任何最佳实践来创建非常安全的令牌(尤其是 Token/Secret 组合)。

在我看来,有几种创建令牌的方法:

    只使用随机字节,存储在与消费者/用户关联的数据库中 散列一些用户/消费者特定的数据,存储在与消费者/用户关联的数据库中 加密用户/消费者特定数据

(1) 的优点是数据库是似乎最安全的信息的唯一来源。比 (2) 或 (3) 更难进行攻击。

散列真实数据 (2) 将允许从可能已知的数据重新生成令牌。可能不会真正为(1)提供任何优势,因为无论如何都需要存储/查找。比 (1) 更占用 CPU。

加密真实数据 (3) 将允许解密知道信息。与 (1) 和 (2) 相比,这将需要更少的存储空间和可能更少的查找,但也可能不太安全。

还有其他需要考虑的方法/优点/缺点吗?

编辑:另一个考虑因素是令牌中必须有某种随机值,因为必须存在过期和重新发行新令牌的能力,因此它不能只包含真实数据。

继续提问

是否有一个最小令牌长度可以显着提高密码安全性?据我了解,更长的令牌秘密会创建更安全的签名。这种理解正确吗?

从散列的角度来看,使用特定编码比使用另一种编码有优势吗?例如,我看到很多 API 使用十六进制编码(例如 GUID 字符串)。在 OAuth 签名算法中,Token 被用作字符串。使用十六进制字符串,可用的字符集将比使用 Base64 编码的字符集小得多(更可预测)。在我看来,对于两个长度相等的字符串,具有较大字符集的字符串将具有更好/更宽的哈希分布。在我看来,这将提高安全性。这个假设正确吗?

OAuth 规范在 11.10 Entropy of Secrets 中提出了这个问题。

【问题讨论】:

为什么要加密?哈希还不够好吗?如果只是散列对于密码来说就足够了,那么对于更长的访问令牌难道不应该更好吗? 我问这个问题已经7.5年了。老实说,我不记得了。 再次阅读,散列和加密是建议的两种不同方法。加密将允许服务器在没有数据库查找的情况下获取一些信息。这是众多权衡中的一种。 【参考方案1】:

OAuth 对令牌只字未提,只是它有一个与之关联的秘密。所以你提到的所有方案都行得通。我们的代币随着网站变大而演变。这是我们之前使用的版本,

    我们的第一个令牌是一个加密的 BLOB,其中包含用户名、令牌秘密和过期时间等。问题是我们无法在主机上没有任何记录的情况下撤销令牌。

    因此我们将其更改为将所有内容存储在数据库中,并且令牌只是用作数据库密钥的随机数。它有一个用户名索引,因此很容易列出用户的所有令牌并撤销它。

    我们很少有黑客活动。使用随机数,我们必须去数据库才能知道令牌是否有效。所以我们又回到了加密的 BLOB。这一次,令牌只包含密钥的加密值和过期时间。所以我们可以在不去数据库的情况下检测无效或过期的令牌。

一些可能对您有所帮助的实现细节,

    在令牌中添加一个版本,这样您就可以在不破坏现有格式的情况下更改令牌格式。我们所有的令牌都有第一个字节作为版本。 使用 URL 安全版本的 Base64 对 BLOB 进行编码,这样您就不必处理 URL 编码问题,这会使 OAuth 签名的调试更加困难,因为您可能会看到三重编码的 basestring。

【讨论】:

太好了,谢谢。版本的想法是一个好主意。我已经使用了 URL 友好的 Base64,但我希望我有一个严格的字母数字编码,以便于阅读。 之前没想到,很有意思!在我阅读本文之前,我正计划使用 APC 密钥缓存来避免数据库的不必要负载。仍然不确定这是否不会比共享内存查找 APC 慢(至少在合理的时间跨度内的第二、第三等请求)。

以上是关于生成 OAuth 令牌的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

参考令牌生成最佳实践

生成重置密码令牌的最佳实践

为忘记密码生成随机令牌的最佳实践

使用 Keycloak 时模拟“生成 API 令牌”的最佳实践

同时从移动设备和 Web 刷新 JWT 令牌的最佳实践

SessionId/Authentication Token 生成的最佳实践