我有一个暴露API端点的ASP.NET core 2.2应用程序。该端点受一个简单的JWT令牌保护,该令牌仅关心主题,过期和签名(使用共享机密的SHA256)。
当我从.net核心客户端调用终结点时,它工作正常。
我现在正试图从Delphi客户端调用相同的代码,但是服务器拒绝了这些令牌,我无法弄清原因:这两个令牌看起来和我一样,并且都通过了jwt.io的验证测试
服务器端令牌验证代码:
private static TokenValidationParameters GetValidationParameters(byte[] key)
{
return new TokenValidationParameters()
{
ValidateLifetime = true,
LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) =>
{
// Cutom validity validation
DateTime current = DateTime.UtcNow; // get a single value for "now"
// check if the token expiration is valid and if it doesn't expire
bool value = (expires.HasValue) && (notBefore.HasValue) && // both "expires" and "notBefore" must be set
(expires >= current) && // "expires" must not be in the past
(expires <= current.AddMinutes(5)) && // "expires" must not be any further than 5 minutes in the future
(notBefore <= current); // notBefore must be in the past or present
return value;
},
RequireExpirationTime = true,
// the token has no audience or issuer so ignore these
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKey = new SymmetricSecurityKey(key)
};
}
private bool ValidateToken(string authToken, byte[] key)
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = GetValidationParameters(key);
// This will raise an exception if the security token is invalid
try
{
tokenHandler.ValidateToken(authToken, validationParameters, out SecurityToken validatedToken);
}
catch (SecurityTokenException e) // this will happen if the token is properly formated but invalid (signature, validity)
{
logger.LogInformation("Invalid token received: {1}", e.Message);
return false;
}
return true;
}
错误发生在tokenHandler.ValidateToken
调用上。永远不会调用令牌到期验证代码。
样本令牌
通过C#应用程序(通过验证):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NjM2MDQ1My1CMDJCLUU5MTEtODM5Qy1BMEE4Q0QzQUNCRjgiLCJuYmYiOjE1NTg2MTMzOTQsImV4cCI6MTU1ODYxMzY5NCwiaWF0IjoxNTU4NjEzMzk0fQ.nso4xnllNc-rXfn5riOWv5fZjNeJMgoQbyXeOltDYb0
在我的Delphi应用程序中(失败):
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2NjM2MDQ1My1CMDJCLUU5MTEtODM5Qy1BMEE4Q0QzQUNCRjgiLCJpYXQiOjE1NTg2MTYxNTgsIm5iZiI6MTU1ODYxNjE1OCwiZXhwIjoxNTU4NjE2NDU4fQ.vB_gotDk1JGiiDWPT0t6TR471Av4r-LXSgc3zab7EaU
报告的错误:
IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey , KeyId:
'.
Exceptions caught:
''.
token: '{"typ":"JWT","alg":"HS256"}.{"sub":"66360453-B02B-E911-839C-A0A8CD3ACBF8","iat":1558616158,"nbf":1558616158,"exp":1558616458}'.
两个令牌都受到相同的共享机密(b64编码)保护:
NdFCOQReqUk0mxTqI7psd9JrVjgE7bdPVfjILEa4dzE=
(所有这些数据均来自本地测试应用程序,因此,毫无疑问会产生此问题)
答案 0 :(得分:0)
我找到了问题,而问题出在我自己身上。
简短的回答:Delphi令牌无效,因为生成签名的代码已被窃听。
我没有注意到这一点,因为每次更改密钥时,JWT.IO都会重新生成令牌签名,因此它始终显示“签名已验证”,因为我的测试例程是“从VisualStudio复制令牌,将其粘贴到JTW调试器中,然后粘贴密钥”,该密钥实际上从未真正验证过原始令牌。
答案 1 :(得分:0)
我得到了这个确切的错误,并花了很长时间试图找出原因。
这是我为仍在寻找它的人提供的正式答案。
在 C# 或 VB 中进行验证时,您必须考虑各种编码。
Dim symmetricKey = (New Guid(secret)).ToByteArray() 'This array encoding is used by .NET
Dim symmetricKeyUTF8 = (Text.Encoding.UTF8.GetBytes(secret)) 'This is used by Javascript and our Postman example
Dim issuerSigningKeys = New List(Of SecurityKey) From {New SymmetricSecurityKey(symmetricKey), New SymmetricSecurityKey(symmetricKeyUTF8)}
还要始终检查秘密是否相同,无论它多么明显。