Sinatra应用如何为“记住我”功能生成安全随机令牌
Sinatra 应用“记住我”登录功能安全实现方案
令牌类型选择
用随机字母数字字符串当令牌完全可行,但要搞清楚核心:选什么字符集不决定安全性,令牌的随机性来源才是核心。
字母数字字符串只是没有特殊字符、不需要额外转义、存储和传输兼容性好的载体,你用URL安全的Base64字符串也完全可以,两者安全性没有本质差别。绝对不要用普通伪随机函数(比如Ruby自带的非安全rand()方法)、或者拼接用户ID、时间戳这类可预测内容生成令牌,这种字符串哪怕做的再长,也有被猜解的风险。
令牌安全长度判定
长度要求的本质是保证令牌的熵值足够大,让暴力破解的成本远高于攻击能拿到的收益,目前身份认证领域通用的最低安全熵值线是128位,对应不同字符集的长度要求:
- 用大小写字母+数字的62字符集时,单个字符约提供5.95位熵,至少需要22个字符,工程上直接取24位留够安全冗余就行
- 用URL安全Base64的64字符集时,单个字符提供6位熵,22个字符刚好满足128位熵要求
如果你的应用用户量级大、存储的数据敏感度高,直接把熵值拉到256位也不会有任何可感知的性能损耗,对应上面两种字符集都取43位即可,安全冗余更足,完全没必要在这个地方省字符。
通用标准开发实践
- 绝对不要发永久有效的记住我令牌:所有令牌必须设置明确过期时间,普通工具类应用设2~4周有效期就够,用户触发修改密码、敏感操作验证时,直接作废该用户名下所有已签发的记住我令牌
- 令牌不要明文存数据库:落库前用SHA-256做一次单向哈希就行,就算数据库拖库,攻击者也拿不到能直接用的有效令牌。校验逻辑也简单,把用户Cookie里带的令牌做同样哈希,和库里存的值比对就行
- 做弱上下文绑定降低被盗风险:可以把令牌和用户首次签发时的User-Agent、IP网段做关联,检测到访问上下文明显异常的时候,强制要求用户重新输密码登录,同时作废当前异常令牌
- 做令牌一次性轮换:用户每次靠记住我令牌自动登录成功后,立刻把旧令牌作废,签发新的令牌返回给客户端,避免令牌被窃后被攻击者长期冒用
- 写Sinatra代码的时候直接用Ruby标准库的
SecureRandom模块生成令牌就行,别自己瞎写随机数逻辑,比如要生成符合要求的24位字母数字令牌,直接调SecureRandom.alphanumeric(24)就完事,底层对接的是操作系统级的密码学安全随机源,完全符合安全要求。
内容的提问来源于stack exchange,提问作者Clare MacAdie
相关产品推荐
相关产品推荐

