所谓的用户登陆
其实就是在网站的每个页面(也就是 每个控制器 的 每个动作 都能取到 current_user)
然后在浏览器里的 cookies 里面存储的是一个没有加密的 hash_string1
然后在数据库里面存储一个加密的 hash_string2 (加密 hash_string1)
然后每个页面通过 cookies 拿到 hash_string1 然后加密之后找到 user 这个找到的 user 就是 current_user
然后就可以对这个 current_user 进行各种蹂躏了对么 亲们?
不是. rails 常用的 devise 没看过源码不清楚。sorcery 和 @rei 在 campo 里自己写的登录逻辑都是记录 user_id。每次请求会自动用 user_id 查询 user 表。
#6 楼 @so_zengtao 用 id 查可以少加一个索引。并且我在 campo 的实现里面没有设 token 字段,而是把 password_digest 再 SHA512 hash 一遍得到一个 token。
#6 楼 @so_zengtao token 只是拿来校验是否过期,当 token + id 给了服务器,服务器会到一张专门记 token 的表查询是否存在,不存在则忽略 id 直接清空 session,反之根据 id 拿到 user 对象
#11 楼 @so_zengtao @Rei 的 campo
刚刚接触 Rails,我也不知道比较安全,高效的做法。
Rails Tutorial 里是每次登录后用 url_base64 生成一段 16 位的字符串(两段字符串碰巧相同的几率非常非常小)姑且叫 remember_token
。然后对这个 16 位字符串做 hash 存到数据库 users 表的一个字段下(为了查询效率这个字段是做 index 的)。你的 app 把 remember_token
存到用户浏览器的 cookie 里。已经登录的用户每次访问页面时,会尝试拿 remember_token
做 hash 去数据库查询用户。当然,为了避免每次都查浪费效率,做了 ||=
处理
self.current_user ||= User.find_by(remember_token_digest: hashed_remember_token)
#14 楼 @so_zengtao @Rei 目前在 Campo 的做法,倘若用户数据泄露,那么攻击者很容易通过 id + password_digest 的 hash 来伪造 remember_token 的?!当然,如果数据库泄露,人家也不用这么麻烦是吧。但可以悄悄做一些恶意的事情。
#16 楼 @so_zengtao Anyway, 这几个方法对 cookie 泄露几乎是无力的。所以用户还是得注意保护自己的敏感数据。
此外,值得注意的是:既然做 hash,那么请务必不要把 hash 前的原始数据暴露出来。无论这个数据是在你的服务器上还是在用户的设备里。