生成重置密码令牌的最佳实践
Posted
技术标签:
【中文标题】生成重置密码令牌的最佳实践【英文标题】:Best practice on generating reset password tokens 【发布时间】:2013-11-29 14:08:55 【问题描述】:关于如何构建重置密码令牌的任何最佳实践?我在想:
随机 17 个字符 [a-zA-Z0-9] + 一个全局唯一 id + 随机 17 个字符 [a-zA-Z0-9]。
是否有更好的解决方案或重置密码令牌的行业标准?
【问题讨论】:
【参考方案1】:有一些要点需要考虑。
-
代码应该是真正随机的(从 MCRYPT_DEV_URANDOM 读取),不应从其他与用户相关的信息中推导出来。
理想情况下,代码采用 base62 编码 (A-Z a-z 0-9),以避免出现 Url 问题。
Store only a hash of the token in the database,否则具有数据库读取权限的攻击者可以重置任何帐户。
这导致在用户点击链接后,您必须在数据库中找到令牌的哈希值。存储令牌有两种可能的方式:
您可以使用 SHA512 之类的哈希算法对令牌进行哈希处理,而无需使用盐。如果令牌非常强(最小长度 20,0-9 a-z A-Z),这是安全的。从理论上讲,您必须在将此类哈希输入数据库之前检查它是否已经存在,实际上这可以忽略不计。我实现了一个可以处理此类令牌的password-reset class。 您使用 BCrypt 和 salt 对令牌进行哈希处理。这允许更短的令牌,但您无法在数据库中搜索散列令牌。相反,您必须在链接中包含 row-id 才能找到令牌。【讨论】:
谢谢你的课 (martinstoeckli.ch/php/StoPasswordReset.zip) 太棒了。特别是generateRandomBase62String()
和hashTokenWithBcrypt()
。太棒了。
关于#3,出于同样的原因,我总是做同样的事情。然而,进一步思考,访问数据库的攻击者不能简单地散列已知的纯文本,将该散列存储在数据库中,然后在密码重置 URL 中使用他选择的纯文本吗?我想攻击者需要访问数据库,以及知道使用了哪种散列算法,但这似乎是一个更小的搜索空间。
@DustinRasener - 获得对数据库的写访问权限比仅读访问权限要困难得多。您可以通过 SQL 注入、丢弃的备份、处置的服务器获得读取访问权限……另一方面,如果攻击者有写入数据库的权限,他不需要重置密码,他可以简单地覆盖密码哈希直接。
有关Should password reset tokens be hashed when stored in a database? 的更多信息。另请注意,您的重置令牌应该过期。
我猜第二个选项在技术上无论如何都会更好地防御在线暴力攻击,因为每次尝试都必须不只是匹配许多用户中的任何一个,而是单个特定用户。尽管实际上,适当的锁定逻辑应该使这方面的任何好处一开始就可以忽略不计。以上是关于生成重置密码令牌的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章