JWT - 解密令牌但不验证
Posted
技术标签:
【中文标题】JWT - 解密令牌但不验证【英文标题】:JWT - Decrypting a Token But Not Validating 【发布时间】:2020-12-12 13:34:57 【问题描述】:My sample project
总结
我创建了一个示例项目来测试 JWT 令牌在 ASP.Net Core 应用程序中的发布。
有关完整示例,请参阅上面的 Github 存储库。
在JwtService.cs类中,有一个方法叫做GenerateSecurityToken,用于生成Jwt token。
AccountController 的 Login 方法调用 JwtService 类生成令牌,将令牌保存在 cookie 中,并为用户 ID 设置另一个 cookie。
注意:令牌使用秘密签名,该秘密还附加了用户特定的盐。用户盐可以随时失效,使用户的令牌失效。
令牌也使用加密密钥加密。这使得令牌的主体在 JWT.io 中检查时难以辨认。我相信它被称为 JWE。
This question 讨论签名和加密顺序。
问题
我不希望持有者或任何第三方检查令牌的内容。令牌在身份验证中的用途。
我的示例代码拦截了身份验证管道,并使用来自 cookie 的电子邮件将用户角色从数据库中提取出来,并从角色中创建角色声明。
你们中的一些人可能已经发现了与电子邮件一起发布单独的 cookie 导致的信息泄露。
理想情况下,我只想在 cookie 中发布 JWE 令牌。
我想拦截身份验证管道,解密令牌,使用电子邮件声明获取用户盐(从数据库)并验证令牌。
我已阅读文档,但无法找到解密令牌的方法。
说实话,我什至不确定颁发令牌时的操作顺序(先签名后加密或先加密后签名)。
如果有人能指出JwtSecurityTokenHandler
的源代码,那可能是一个好的开始。
TIA
public string GenerateSecurityToken(string email, byte[] salt, string[] roles)
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_secret).Concat(salt).ToArray();
byte[] ecKey = new byte[256 / 8];
Array.Copy(Encoding.ASCII.GetBytes(_ecKey), ecKey, 256 / 8);
var tokenDescriptor = new SecurityTokenDescriptor
Issuer = _issuer,
Audience = _audience,
Subject = new ClaimsIdentity(
new List<Claim>
new Claim(ClaimTypes.Email, email)
),
// .Concat(roles.Select(r => new Claim(ClaimTypes.Role, r))).ToArray()),
Expires = DateTime.UtcNow.AddMinutes(double.Parse(_expDate)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
EncryptingCredentials = new EncryptingCredentials(
new SymmetricSecurityKey(
ecKey),
SecurityAlgorithms.Aes256KW,
SecurityAlgorithms.Aes256CbcHmacSha512)
;
var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
【问题讨论】:
您发布的Token不完整,请编辑完整发布,同时提供其他相关类代码识别缺失/错误部分 感谢您的反馈。我已经编辑了原始问题,添加了指向我的示例项目的链接并使其更加简洁。 我认为 JwtSecurityTokenHandler 的源代码在这里.. github.com/AzureAD/… 如果我能解决我的问题会更新。 更新 2:DecryptToken
受到保护。我将尝试创建一个继承自JwtSecurityTokenHandler
的新类并公开该方法。 ``` 受保护的字符串 DecryptToken(JwtSecurityToken jwtToken, TokenValidationParameters 验证参数) ``
【参考方案1】:
虽然您对散列 JWT 非常感兴趣,但我建议您使用四种方法:
生成令牌(顺序很重要):
-
生成令牌
哈希令牌
那么当你收到带有请求的承载令牌时(顺序很重要):
-
DeHashToken
验证令牌
作为两个过程,JWT 生成和散列非常简单:
为了获得最佳结果,忘记散列并专注于生成令牌和验证令牌。
在您使用 JWT 取得成功后,在一个单独的项目中,专注于对任何文本(JWT 或其他)进行散列和去散列处理。
当你们都成功了,不要互相呼唤。
构建新方法,例如
-
GenerateAndHash(它同时调用 GenerateToken 和 HashToken)
VerfyHashAndValidateToken(同时调用 DeHashToken 和 ValidateToken)
To Generate and Validate JWT step by step see this(文章的标题可能令人困惑,但它以非常简单的方式讨论了 .NET Core 中的 JWT,尤其是在第 2 部分我认为)
https://www.codemag.com/Article/1805021/Security-in-Angular-Part-1
https://www.codemag.com/Article/1809031/Security-in-Angular-Part-2
https://www.codemag.com/Article/1811031/Security-in-Angular-Part-3
散列
public static string ToCustomHash(this string text)
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
var pbkdf2 = new Rfc2898DeriveBytes(text, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
var hashedToBase64 = Convert.ToBase64String(hashBytes);
return hashedToBase64;
验证哈希
public static bool VerifyHashWith(this string storedPassword, string loginPassword)
byte[] hashBytes = Convert.FromBase64String(storedPassword);
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
var pbkdf2 = new Rfc2898DeriveBytes(loginPassword, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
for (int i = 0; i < 20; i++)
if (hashBytes[i + 16] != hash[i]) return false;
return true;
【讨论】:
以上是关于JWT - 解密令牌但不验证的主要内容,如果未能解决你的问题,请参考以下文章