在当今的网络世界中,安全性是应用程序开发中至关重要的一个方面。随着用户数量和数据量的增加,保护用户数据和验证用户身份变得尤为重要。JSON Web Token(JWT)作为一种安全且可扩展的身份验证方案,越来越受到开发者的青睐。本文将深入探讨 JWT 的工作原理、优势和如何在应用程序中使用它来增强安全性。
什么是 JSON Web Token(JWT)?
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络应用中传输信息的简洁、自包含的方式。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三部分由点号(.)分隔开来,形成了一个具有一定结构的字符串,如 xxxxx.yyyyy.zzzzz。
JWT的结构:
-
头部(Header)
头部通常由两部分组成,即令牌的类型(typ)和所使用的算法(alg)。例如,一个头部可能是 {"alg": "HS256", "typ": "JWT"},表示使用 HMAC SHA-256 算法对令牌进行签名。
-
载荷(Payload)
载荷包含了 JWT 的声明信息,用于描述令牌的相关内容。载荷可以包含标准声明(例如:发行者、主题、过期时间等),也可以包含自定义声明。例如,一个载荷可能是 {"sub": "1234567890", "name": "John Doe", "exp": 1516239022}。
-
签名(Signature)
签名用于验证令牌的完整性和真实性。签名通常由头部、载荷和密钥一起计算而得。验证者可以使用相同的密钥重新计算签名,并将结果与令牌中的签名进行比较,以确认令牌的真实性。
JWT 的算法
JWT 支持多种签名算法,常用的包括 HMAC 算法和 RSA 算法。以下是常见的 JWT 签名算法:
-
HMAC(Hash-based Message Authentication Code)
HMAC 算法是一种基于哈希函数的消息认证码,通过将密钥和消息作为输入,生成一个固定长度的哈希值。常见的 HMAC 算法包括 HMAC SHA-256、HMAC SHA-384 和 HMAC SHA-512 等。
-
RSA(Rivest-Shamir-Adleman)
RSA 算法是一种非对称加密算法,使用一对公钥和私钥来对数据进行加密和解密。JWT 使用 RSA 算法可以实现更安全的签名和验证过程。
-
ECDSA(Elliptic Curve Digital Signature Algorithm)
ECDSA 算法是一种基于椭圆曲线的数字签名算法,可以实现较短的密钥长度和更高的安全性。
JWT的生成过程
上面讲了那么多,那么到底jwt token是怎么生成出来的呢?
- 首先根据你选择的算法生成头部(Header),例如常用的HS256,那么我们的头部信息就是{"alg": "HS256", "typ": "JWT"}。然后把头部信息base64编码。
- 定义自己的payload,然后base64编码;
- 把步骤1和步骤2生成的base64字符串用"."拼接起来,形成未签名的JWT Token
- 使用指定密钥对未签名的Token进行签名。
- 将未签名和签名的结果用"."连接起来形成最终的JWT Token
C#
using System;
using System.Text;
using System.Security.Cryptography;
class Program
{
static void Main(string[] args)
{
// 定义密钥
string secretKey = "my_secret_key_123456789";
// 创建 Payload
string payload = "{\"sub\":\"user_id\",\"email\":\"user@example.com\",\"jti\":\"" + Guid.NewGuid().ToString() + "\"}";
// 创建 JWT Token
string token = GenerateToken(payload, secretKey);
Console.WriteLine("Generated JWT token:");
Console.WriteLine(token);
}
static string GenerateToken(string payload, string secretKey)
{
// 创建 Header
string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
// 编码 Header 和 Payload
string encodedHeader = Base64UrlEncode(header);
string encodedPayload = Base64UrlEncode(payload);
// 创建 Signature
string dataToSign = encodedHeader + "." + encodedPayload;
byte[] signatureBytes;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey)))
{
signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
}
string encodedSignature = Base64UrlEncode(signatureBytes);
// 将 Header、Payload 和 Signature 拼接成 JWT Token
return $"{encodedHeader}.{encodedPayload}.{encodedSignature}";
}
static string Base64UrlEncode(string input)
{
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
return Base64UrlEncode(inputBytes);
}
static string Base64UrlEncode(byte[] inputBytes)
{
string base64 = Convert.ToBase64String(inputBytes);
return base64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
}
}
JWT 的优势
- 无状态性:JWT 是无状态的,服务器不需要在后端存储会话信息,减轻了服务器负担。
- 安全性:JWT 使用签名来验证令牌的真实性,防止了篡改和伪造。
- 可扩展性:JWT 可以通过在 Payload 中添加自定义的声明来传递任意数据,实现了更多的功能。
- 跨语言:JWT是一种跨语言的标准,因为它使用 JSON 格式作为数据载体,并且它的标准规范是语言无关的。这意味着无论使用哪种编程语言编写的应用程序,都可以轻松地生成和解析 JWT。
JWT的缺点
-
无法撤销令牌:一旦颁发了 JWT,就无法在令牌的有效期内撤销它。即使用户的权限发生变化或者令牌被泄露,令牌也仍然有效,直到过期时间到期为止。
-
安全性依赖于签名算法:JWT 的安全性取决于签名算法的强度。如果使用了弱算法或者密钥管理不当,可能会导致签名被破解,从而使得 JWT 变得不安全。
-
无法处理令牌刷新:JWT 本身不提供令牌刷新功能,需要额外的机制来实现。这使得在令牌到期后,客户端需要重新进行身份验证,可能会增加一定的复杂性。
-
不适合存储敏感信息:JWT 虽然可以对 Payload 进行加密,但是加密后的 Payload 仍然可以被解析出来。因此,不建议在 JWT 中存储敏感信息,如密码等。
如何在应用程序中使用 JWT?
- 用户认证:用户登录时,服务器验证用户身份,并生成 JWT 返回给客户端。
- 访问授权:客户端在每次请求时,将 JWT 放在请求头中发送给服务器。
- 验证身份:服务器接收到请求后,验证 JWT 的签名和有效期,从而确认用户身份。
说明&注意事项
-
为每个第三方应用分配AppId/LoginKey
-
Token由我方服务端生成(格式/内容)
-
第三方获取Token后应该缓存一段时间
-
第三方不需要知道Token的数据内容
-
第三方调用服务接口时,必须携带Token
-
保护好Token密钥,绝对不能公开给第三方
错误实践
客户端直接生成Token!
会有哪些问题?
- 密钥泄露,导致签名无意义
- 内容不可控
- 数据结构难以更新
结语
JSON Web Token(JWT)作为一种安全、可扩展的身份验证方案,在网络应用开发中发挥着越来越重要的作用。通过了解 JWT 的工作原理、优势和在应用程序中的使用方式,我们可以更好地保护用户数据,提升应用程序的安全性和可扩展性。
如果你还没有开始使用 JWT 来增强你的应用程序的安全性,那么现在就是时候开始了!
更多一手讯息,可关注公众号:ITProHub