token验证机制及实现.md

在中心服务器模式下的客户端认证

又发现了一项之前在工行工作期间缺失的技术,到了互联网企业工作后,技术栈大大不同。http协议是无状态的,但是网站登录要求前后几次请求能被标志为同一个人发起,工行是在服务器端管理,负担重;互联网企业是在客户端自行管理,体现了一定的p2p思想

认证类型
  • 每次请求都带上用户名和密码

    • 优点:实现简单

    • 缺点:频繁传输容易有安全风险;不能给第三方

    • 缺点:问题是密码怎么存?如果每次都要输入用户名密码,用户体验也不好;如果存下来,有安全隐患

  • 服务器集中维护session;客户端有对应的cookie保存session id

    • 优点是一次登录后就不用输入密码了;但是缺点很多,首先是服务器内存压力大,要来维护session,其次是不能动态扩展,另外是存在浪费,比如用于直接关闭了浏览器后只能超时退出
  • token验证机制,反客为主,由客户端来管理和验证session

    • 服务器压力小,客户来了给看一下,不用给设置15分钟超时之类的,不必时时刻刻管着客户的事情

    • 相当于颁发了一张证书给客户端,里面规定了这个客户有效登录和超时时间,并有服务器对此的签名,然后服务器就不管了

这篇写的很好

基于token的web后台认证机制

v2ex的讨论


sessionId方式和token方式区别

token验证机制及实现.md_第1张图片


从认证看中心化和去中心化
  • 工行的认证是完全的中心化

  • 移动支付的方式是集群化,体现了一定的去中心化

  • 以太坊的认证是完全的去中心化!!


JWT

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名
  • 头部

{
"typ": "JWT",
"alg": "HS256"  //签名算法
}
  • 载荷

{ "iss": "Online JWT Builder",   //签发者issue
  "iat": 1416797419,  //签发时间
  "exp": 1448333419,  //过期时间
  "aud": "www.example.com",  //接受方
  "sub": "[email protected]",   //订阅者
  "Email": "[email protected]", 
  "Role": [ "Manager", "Project Administrator" ] 
}
  • 签名

有私钥的,对如上两个部分签名

用户登录时,提供了密码(口令),这个口令理论上只有用户本人知道,所以完成了认证,其实也可以用指纹


JDK 中提供了非常方便的 BASE64EncoderBASE64Decoder,用它们可以非常方便的完成基于 BASE64 的编码和解码


import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import io.jsonwebtoken.*;
import java.util.Date;    
 
//Sample method to construct a JWT
 
private String createJWT(String id, String issuer, String subject, long ttlMillis) {
 
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
 
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
 
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(apiKey.getSecret());
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
 
  //Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)  //会话id
                                .setIssuedAt(now)  //签发时间
                                .setSubject(subject) //签发给谁
                                .setIssuer(issuer)   //签发者
                                .signWith(signatureAlgorithm, signingKey);
 
//if it has been specified, let's add the expiration
if (ttlMillis >= 0) {
    long expMillis = nowMillis + ttlMillis;
    Date exp = new Date(expMillis);
    builder.setExpiration(exp);
}
 
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}




基于 sesssion :不带身份证,只脑袋记住身份证号码,到火车站报一下身份证号码,从后台调出照片比对一下。

基于token :随身带着身份证,以后你只要出示这张出示,带pos机本地检查一下(不需要连接后台),我就知道你一定是自己人。 就是身份证丢失了很麻烦


攻击防范

  • 窃听:只能用https了,最新趋势是用硬件加速https

  • 重放:加入时间戳,保证token快速过期

一般要两者结合起来

HS256就是 hmac_hash256,防止篡改(因为没有密码),防止服务器以外的人伪造(只有服务器知道密码)

token泄露或者sessionid泄露的问题:rfc的专家早就考虑了

RFC 6819 - OAuth 2.0 Threat Model and Security Considerations

  • 对于链路传输层,rfc给的建议是:全部上https,走可靠链路。哪么中间就不会有人泄漏啦。(不提HeartBleed 啊,只是实现bug,不是协议bug,大规模https/TLS的hack还没有出现,我们可以认为https是安全的。此观点答主不和任何人辩论)
  • 对于终端Endpoints的泄漏。不好意思。rfc啥都没说。意思就是,我们不care。

token的不可撤销(只能等待失效)和无法更改问题有解决方案了

用两套token: Access & refresh token签名tokens

  • Access token拥有比较短的生存时间, 可以被认作为一个无状态的可信任的字符串。临时通行证

  • Refresh token拥有比较长的生存时间,是用来换取access token的。refresh token应该可以被撤销(Database + cache). 长期身份证(只记载不变信息,比如id和姓名,数据库对应有记录其失效日期,每次开会兑换临时通行证

|应用场景|Access Token| Refresh Token|

|------------|------------------|--------------------|

|银行应用|1分钟 |30分钟|

|普通应用|5分钟 |2小时|

|新闻应用|1小时 |2年|

签名和验签时间对比,果然相差很大
  • 4096位RSA私钥公钥对 签名 --> 每个49.36ms, 验签 --> 每个 0.6667ms

  • 2048位RSA私钥公钥对 签名 --> 每个6.43ms, 验签 --> 每个 0.1844ms

  • 1024位RSA私钥公钥对 签名 --> 每个1.088ms, 验签 --> 每个 0.0548ms


几种鉴别方式比较

系统和用户有边界。用户怎么证明“我是我”?

信息私密性分组,“只有你才知道的秘密”,私密体是信息
  • 用户名密码。简短,唯一用户才知道,需要用户名和密码的对应关系。私密性。需要用户说出“我是谁”

  • 公钥私钥,这个像是用户名和密码的超级升级版本

  • 短信验证。手机号就是用户名,短信验证码就是密码。也是唯一用户才知道,需要用户名和密码的对应关系。

  • 动态密码生成器(比如将军令)。其实也是靠初始序号的秘密性。虽然是动态,本质还是密码。

信物 “只有你才拥有的物品”,私密体是某个物品
  • 古老的信物。某只特殊的鞋子,玉镯。。(这个东西要比较特别才行,若干年后无论谁拿到了,就是认这个物品)

  • U盾。只要无法克隆这个U盾,就是安全的。

  • 生物识别,指纹,人脸,虹膜。用独一无二的生物特征。不需要用户说出“我是谁”

  • token(介于信息和物品之间),是服务器颁发的防伪证书。不需要用户说出“我是谁”,但是需要上送用户id,时间,权限等核对一下

    • token比较特殊,第一次,用户要用户名密码或者其他方式认证后,才颁发token;他没法单独使用;其他都可以单独使用

你可能感兴趣的:(全栈,互联网开发,互联网架构,jwt,token,认证,session,acl)