IDX10503:签名验证失败。托肯没有孩子。尝试过的键:“System.Text.StringBuilder”

use*_*567 15 c# security jwt identitymodel

我有以下 JWT 令牌,

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjbGllbnRpZCIsImF1ZCI6ImNsaWVudGlkIiwic3ViIjoiMTIzIiwiYSI6IjQ1NiIsImlhdCI6MTYyMTc5OTU5OCwiZXhwIjoxNjIxNzk5NjU4fQ.hglbX63zhPwTOsB-zSiOMfxEKl5OaIk6zX1o9-LEhP3nro8fa5_3QyIH7I5971j-xuO1bccX1TOh0kNcQ-ACAg
Run Code Online (Sandbox Code Playgroud)

这是使用生成的,

    public static string GenerateToken(string key, string a1, string a2)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var token = new JwtSecurityToken(
            claims: new Claim[]
            {
            new Claim(JwtRegisteredClaimNames.Iss, "clientid"),
            new Claim(JwtRegisteredClaimNames.Aud, "clientid"),
            new Claim(JwtRegisteredClaimNames.Sub, a1),
            new Claim("a", a2),
            new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
            },
            //notBefore: new DateTimeOffset(DateTime.Now).DateTime,
            expires: new DateTimeOffset(DateTime.Now.AddMinutes(1)).DateTime,
            signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha512)
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

var key = "Ym7AD3OT2kpuIRcVAXCweYhV64B0Oi9ETAO6XRbqB8LDL3tF4bMk9x/59PljcGbP5v38BSzCjD1VTwuO6iWA8uzDVAjw2fMNfcT2/LyRlMOsynblo3envlivtgHnKkZj6HqRrG5ltgwy5NsCQ7WwwYPkldhLTF+wUYAnq28+QnU=";
// Key is test                
var token = GenerateToken(key, "123", "456");
Run Code Online (Sandbox Code Playgroud)

获得令牌后,我使用下面的代码进行验证,

var key = "Ym7AD3OT2kpuIRcVAXCweYhV64B0Oi9ETAO6XRbqB8LDL3tF4bMk9x/59PljcGbP5v38BSzCjD1VTwuO6iWA8uzDVAjw2fMNfcT2/LyRlMOsynblo3envlivtgHnKkZj6HqRrG5ltgwy5NsCQ7WwwYPkldhLTF+wUYAnq28+QnU=";
// key is test

var hmac = new HMACSHA512(Convert.FromBase64String(key));
var validationParameters = new TokenValidationParameters
            {
                ValidAudience = "clientid",
                ValidIssuer = "clientid",
                IssuerSigningKey = new SymmetricSecurityKey(hmac.Key)
            };
            var tokenHandler = new JwtSecurityTokenHandler();
            return tokenHandler.ValidateToken(token, validationParameters, out var validToken);
Run Code Online (Sandbox Code Playgroud)

但我遇到了以下错误,

IDX10503: Signature validation failed. Token does not have a kid. Keys tried: 'System.Text.StringBuilder'.
Exceptions caught:
 'System.Text.StringBuilder'.
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.
Run Code Online (Sandbox Code Playgroud)

use*_*567 19

问题是这一行,

var hmac = new HMACSHA512(Convert.FromBase64String(key));
Run Code Online (Sandbox Code Playgroud)

我把它改成了,

var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
Run Code Online (Sandbox Code Playgroud)

该错误具有误导性。该错误的源代码位于https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/d6f2b66d788195b50f2b1f700beb497851194c73/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs#L1016

  • 做得好。任何时候“string.IsNullOrEmpty(jwtToken.Header.Kid);”发生并且“keysAttempted.Length > 0”都会引发错误,这是误导性的。 (3认同)

小智 11

除了能够使用上面演示的 Base64 编码键值之外,您还可以使用字符串。但也有一些注意事项。

\n

使用 SymmetricSecurityKey 创建 HMACSHA256 或 HMACSHA512 的处理程序不会对哈希大小执行零位填充(根据 RFC2104,步骤 1),这会导致签名算法失败。如果用作密钥的字符串大于密钥大小(256 或 512 位),则一切正常。

\n

以下是为较短的签名字符串生成适当的 SymmetricSecurityKey 的两种方法:

\n

第一种方法:手动用零字节填充字符串并生成 Base64 密钥。像 Cyber​​Chef 这样的东西可以用来将 /0 字符附加到 256 位的 32 个字符或 512 位的 64 个字符:

\n

通过 Cyber​​Chef 手动生成 Base64 密钥

\n

这些密钥将生成相同的 JWT

\n

JWT.io 中的等效键

\n

这可以像上面 Imran 所演示的那样使用......

\n
// Set up the signingKey for HS256\n// Base64 signingKey\n//SymmetricSecurityKey signingKey = new SymmetricSecurityKey(Convert.FromBase64String("c2VjcmV0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="));\n
Run Code Online (Sandbox Code Playgroud)\n

第二种方法:在不进行 base64 转换的情况下,SymmetricSecurityKey 将采用 ascii byte[],只要您已经完成了填充:

\n
// Short String signingKey\n// Note: Not advised. Short keys can be bruteforced, allowing tokens to be forged. \n// Note: manually padding to 256 bits if it is a short key, as the SymmetricSignatureProvider does not do the HMACSHA256 RFC2104 padding for you.\n// SymmetricSecurityKey signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secret".PadRight((256/8), \'\\0\')));\nSymmetricSecurityKey signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secret".PadRight((512/8), \'\\0\')));\n
Run Code Online (Sandbox Code Playgroud)\n

无论采用哪种方法,您都可以在默认的 JwtBearer 处理程序中使用生成的 SymmetricSecurityKey:

\n
builder.Services.AddAuthentication(options => {\n    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\n}).AddJwtBearer(options => {\n    options.TokenValidationParameters = new TokenValidationParameters\n    {\n        ValidateAudience = true,\n        ValidateIssuer = true,\n        ValidIssuer = "https://localhost:7046/",\n        ValidAudience = "https://localhost:7046/",\n        RequireSignedTokens = true,\n        IssuerSigningKey = signingKey,\n        ValidateLifetime = true\n    };\n});\n\nbuilder.Services.AddAuthorization(auth =>\n            {\n                auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()\n                        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme\xe2\x80\x8c\xe2\x80\x8b)\n                    .RequireAuthenticatedUser().Build());\n            });\n
Run Code Online (Sandbox Code Playgroud)\n

最后一点,我在添加 Microsoft.IdentityModel.Tokens 包的一项测试中遇到了一些问题。我仍然需要运行它,但该包中可能存在冲突的类......

\n

我这里有一个使用这种方法的示例:GitHub 中的示例项目

\n

值得注意的是,不建议为 HMAC 使用短对称密钥,因为该秘密可以相对轻松地被暴力破解,尤其是当它出现在已知密码列表中时。值得检查一下您过去的HaveIBeenPwned - PwnedPasswords密钥,以确信它以前是否被使用过。这主要是为创建短 HMAC 演示的人们提供的。如果您对使用 PwnedPasswords 感到不舒服,请参阅以下有关他们使用的K-匿名模型的内容,并在浏览器工具中观察网络选项卡时进行实验,看看它是如何工作的。

\n