欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

token验证机制及实现.md

程序员文章站 2022-07-02 23:36:51
...

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

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

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

    • 优点:实现简单

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

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

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

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

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

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

这篇写的很好

基于token的web后台认证机制

v2ex的讨论


sessionId方式和token方式区别

token验证机制及实现.md


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

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

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


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": "aaa@qq.com",   //订阅者
  "Email": "aaa@qq.com", 
  "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;他没法单独使用;其他都可以单独使用