基于Token的身份验证——JWT

引言:基于Token的身份验证用来替代传统的cookie+session身份验证方法中的session。

1、JWT是什么

JSON Web Token (JWT) 使用一种基于签名的机制来确保数据的完整性和安全性,以便能够验证其真实性。JWT 并不是加密的,而是使用签名来验证其内容是否被篡改。下面我将解释 JWT 是如何工作的以及为什么它们通常是安全的。

JWT 通常由三部分组成:Header、Payload 和 Signature。

  1. Header(头部):Header 包含有关 JWT 的元数据和签名算法的信息。这部分通常是 Base64 编码的,但它并不是加密的,只是编码,所以可以很容易地被解码。

  2. Payload(荷载):Payload 包含有关用户或实体的声明和数据。这部分通常是 Base64 编码的,但它并不是加密的,只是编码,所以可以很容易地被解码。

  3. Signature(签名):Signature 是对 Header 和 Payload 的签名。这部分通常是使用签名算法(例如 HMAC SHA256)和密钥(通常被称为 JWT secret)对 Header 和 Payload 数据签名而生成的,这个签名用于验证 JWT 的完整性和真实性。

JWT形式如下:

A.B.C

1.1 怎样生成A?

header格式为:

{
    "typ": "JWT",
    "alg": "HS256" 
}

它就是一个json串,两个字段是必须的,不能多也不能少。alg字段指定了生成C的算法,默认值是HS256
将header用base64编码,得到A
通常,JWT库中,可以把A部分固定写死,用户最多指定一个alg的取值

1.2 怎样计算B?

根据JWT claim set[用base64]加密得到的。claim set是一个json数据,是表明用户身份的数据,可自行指定字段很灵活,也有固定字段表示特定含义(但不一定要包含特定字段,只是推荐)。
这里偷懒,直接用php中的代码来表示claim set了,重在说明字段含义:

$token = array(
    "iss" => "http://example.org",   #非必须。issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者。
    "iat" => 1356999524,                #非必须。issued at。 token创建时间,unix时间戳格式
    "exp" => "1548333419",            #非必须。expire 指定token的生命周期。unix时间戳格式
    "aud" => "http://example.com",   #非必须。接收该JWT的一方。
    "sub" => "jrocket@example.com",  #非必须。该JWT所面向的用户
    "nbf" => 1357000000,   # 非必须。not before。如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟。
    "jti" => '222we',     # 非必须。JWT ID。针对当前token的唯一标识

    "GivenName" => "Jonny", # 自定义字段
    "Surname" => "Rocket",  # 自定义字段
    "Email" => "jrocket@example.com", # 自定义字段
    "Role" => ["Manager", "Project Administrator"] # 自定义字段
);

JWT遵循RFC7519,里面提到claim set的json数据中,自定义字段的key是一个string,value是一个json数据。因此随意编写吧,很灵活。

个人初学,认为一个最基本最简单最常用的claim set为:

$token=array(
    "user_id" => 123456, #用户id,表明用户
    "iat" => 1356999524, #token发布时间
    "exp" => 1556999524, #token过期时间
);

将claim set用base64编码得到B,学名payload

1.3 怎样计算C?

服务器使用 JWT 的头部 (Header) 和负载 (Payload) 数据,以及一个密钥(通常被称为 JWT secret,其实就是一个字符串)作为输入,使用指定的签名算法(例如 HMAC SHA256,其实是用header中指定的算法)来生成 Signature。生成的 Signature 会被附加到 JWT 的末尾,形成完整的 JWT 令牌。

客户端收到 JWT 后,可以使用相同的密钥和相同的签名算法来验证令牌的完整性。它会提取 Header 和 Payload 数据,然后使用相同的密钥和签名算法重新计算 Signature。如果新生成的 Signature 与 JWT 中的 Signature 相匹配,那么说明令牌没有被篡改。(非必需步骤)

好了,现在A.B.C就是生成的token了。这种签名机制确保了 JWT 在传输过程中的完整性和真实性,防止了篡改令牌数据的尝试。因此,保护 JWT 密钥的安全性非常重要,以防止未经授权的签名操作。如果 JWT 用于身份验证和授权,建议密钥的生成和存储要得到妥善处理,以确保安全性。

2、JWT 的工作流程

JWT 的工作流程如下:

  • 服务器在创建 JWT 时,使用签名算法和密钥对 Header 和 Payload 进行签名生成 Signature。
  • 客户端收到 JWT 后,可以对 Header 和 Payload 进行解码,但无法修改 Signature,因为它需要服务器的密钥来重新生成。如果其中任何一部分被篡改,Signature 将无效。
  • 当客户端将 JWT 发回服务器时,服务器使用相同的密钥和签名算法重新计算 Signature来验证 JWT 的 Signature,以确保它没有被篡改。

这意味着,JWT 是安全的,只要密钥保持机密并且只有服务器能够生成有效的签名。但是,如果密钥被泄露或者服务器的签名算法存在漏洞,那么攻击者可能会创建伪造的 JWT 或者解密其中的数据。因此,保护密钥的安全性非常重要。

3、客户端怎样使用token

可以放到HTTP请求的请求头中,通常是Authorization字段。
也有人说放到cookie。不过移动端app用cookie似乎不方便。

token应用流程:

  1. 初次登录:用户初次登录,输入用户名密码
  2. 密码验证:服务器从数据库取出用户名和密码进行验证
  3. 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
  4. 返还JWT:服务器的http response中将JWT返还
  5. 带JWT的请求:以后客户端发起请求,http request header的Authorization字段都要有值,为JWT

4、总结

总的来说,如果正确地实施和使用,JWT 通常是安全的。然而,它也可能存在一些潜在的风险,例如密钥泄漏、未能验证有效期限或选择不安全的算法。因此,在实施 JWT 时,需要遵循最佳实践,确保密钥的安全性,并定期审核和更新系统以防范潜在的威胁。
posted @ 2017-08-16 09:09  人艰不拆_zmc  阅读(846)  评论(0编辑  收藏  举报