请求中的token机制
where(场景)
1、csrf的服务端token
# 首先生成真实的raw_token并存到session或cookie中
def real_csrf_token(session) # :doc:
session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
Base64.strict_decode64(session[:_csrf_token])
end
# 看到raw_token 只是一个已知长度的随机字符串,然后再base64之后,存到session中
raw_token = real_csrf_token(session)
# 给客户端的,客户端构造给表单hidden或ajax的mask_token
def mask_token
one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token) # xor计算
masked_token = one_time_pad + encrypted_csrf_token
Base64.strict_encode64(masked_token)
end
# mask_token在前端页面是可以看到的
# 如果进行对比校验?
# 将前端传过来的masked_token 进行unmask 得到一个 unmask_token 再和session中的session[:_csrf_token]进行比较,相等说明校验通过,unmask 的过程就是mask的逆向过程
def unmask_token(masked_token) # :doc:
one_time_pad = masked_token[0...AUTHENTICITY_TOKEN_LENGTH]
encrypted_csrf_token = masked_token[AUTHENTICITY_TOKEN_LENGTH..-1]
xor_byte_strings(one_time_pad, encrypted_csrf_token)
end
unmask_token == session[:_csrf_token] ? Yes : No
诠释:
- 在这一次session的生命周期中,
session[:_csrf_token]
是固定的 - 每次给前端的mask_token是不一样的,是因为每次的
one_time_pad
是不一样的 - 但是,每次将mask_token unmask逆向之后得到的real_token应该是一样的,然后和
session[:_csrf_token]
比较即可
如果攻击者要破解CSRF token,他需要能够在session这次生命周期内拿到session[:_csrf_token]
如果session[:_csrf_token]
存在cookie中,攻击者需要破解cookie得到真实数据。(防止方案:可以设置cookie的httponly属性为true,这样cookie就只能通过服务器读取不能通过javascript读取)
2、部分代替分布式session的能力:
跨站点方案:
JWTtoken结构:
本身可以带 uid 信息、校验信息,解密后就可以获取。
token 主要由三部分组成 :
1. header:指定了签名算法 ;
2. payload:可以指定用户 id,过期时间等非敏感数据 ;
3. Signature: 签名。server 根据 header 知道它该用哪种签名算法,再用密钥根据此签名算法对 head + payload 生成签名。
payload字段:Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用,如下:
其实,还可以在这个部分定义私有字段 。JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
JWT 的最大缺点:
由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就> 是说,一旦 JWT 签发了,在到期之前就会始终有效。
合法性验证:
server 收到浏览器传过来的 token 时,它会首先取出 token 中的 header + payload,根据密钥(服务端知道)生成签名,然后再与 token 中的签名比对,如果成功则说明签名是合法的,即 token 是合法的。
后面就可以使用payload中的信息了。
使用流程: