将 SymmetricSecurityKey 替换为 JWT 的非对称安全密钥

Jay*_*y1b 5 c# cryptography rsa jwt

渗透测试建议我们更改 JWT 实现以使用非对称签名而不是对称签名,这种方法运行良好。

创建对称令牌的当前(完美工作)代码如下:(灵感最初来自如何加密 JWT 安全令牌?

private string CreateToken(string Username)
        {
            //Set issued at date
            DateTime issuedAt = DateTime.UtcNow;
            //set the time when it expires
            DateTime expires = DateTime.UtcNow.AddHours(1);

            
            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

            //create a identity and add claims to the user which we want to log in
            ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, Username)
            });

            DateTime now = DateTime.UtcNow;
            SymmetricSecurityKey securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
            SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

            //create the jwt
            JwtSecurityToken token = tokenHandler.CreateJwtSecurityToken(issuer: "issuer",
                                                                         audience: "audience",
                                                                         subject: claimsIdentity,
                                                                         notBefore: issuedAt,
                                                                         expires: expires,
                                                                         signingCredentials: signingCredentials);

            return tokenHandler.WriteToken(token);

        }
    }
Run Code Online (Sandbox Code Playgroud)

检查任何 API 调用请求的代码类似于以下内容:

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            HttpStatusCode StatusCode;
            string token;

            //determine whether a jwt exists or not
            if (!TryRetrieveToken(request, out token))
            {
                StatusCode = HttpStatusCode.Unauthorized;
                //allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
                return base.SendAsync(request, cancellationToken);
            }

            try
            {
                DateTime now = DateTime.UtcNow;
                SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));

                SecurityToken securityToken;
                JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
                TokenValidationParameters validationParameters = new TokenValidationParameters()
                {
                    ValidAudience = "audience",
                    ValidIssuer = "issuer",
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    LifetimeValidator = this.LifetimeValidator,
                    IssuerSigningKey = SecurityKey
                };

                //extract and assign the user of the jwt
                Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
                HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);

                return base.SendAsync(request, cancellationToken);
            }
            catch (SecurityTokenValidationException e)
            {
                StatusCode = HttpStatusCode.Forbidden;
            }
            catch (Exception ex)
            {
                StatusCode = HttpStatusCode.Forbidden;
            }
            return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(StatusCode) { });
        }
Run Code Online (Sandbox Code Playgroud)

我已经在网上尝试了很多示例并阅读了很多帖子,但还没有任何工作,每个示例都有很多不同的问题。我得到的关闭可能是遵循以下一些示例: RS256 vs HS256:有什么区别?

下面的一个示例似乎可以用于创建代码,但在将令牌与传入的 API 调用进行比较时,这将不起作用。

                RSA _rsaa;
                _rsaa = new RSACryptoServiceProvider(2048);
                var r = _rsaa.ExportParameters(true);
                SigningCredentials signingCredentials3a = new SigningCredentials(new RsaSecurityKey(_rsaa), SecurityAlgorithms.RsaSha256Signature);
Run Code Online (Sandbox Code Playgroud)

最后,下面的选项感觉是正确的,但得到的是“提供者的错误版本”。由于字符串中保存的加密密钥内容而导致错误。

            byte[] Key256Bytes = Encoding.ASCII.GetBytes(Key256);

                rsa.ImportCspBlob(Key256Bytes);
                SigningCredentials signingCredentials5 = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256Signature);
Run Code Online (Sandbox Code Playgroud)

我很难让各种选项发挥作用。

Jay*_*y1b 10

找到了解决办法,将上面的转换成非对称加密,交换:

SymmetricSecurityKey securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
Run Code Online (Sandbox Code Playgroud)

var rsa = new RSACryptoServiceProvider(); 
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));                
SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha512Signature);
Run Code Online (Sandbox Code Playgroud)

加密密钥是使用以下内容生成的。

var rsa = new RSACryptoServiceProvider(2048);
var key = Convert.ToBase64String(rsa.ExportCspBlob(true));
Run Code Online (Sandbox Code Playgroud)

然后在检查传入的 JWT 时:

SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
Run Code Online (Sandbox Code Playgroud)

var rsa = new RSACryptoServiceProvider();      
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));
RsaSecurityKey SecurityKey = new RsaSecurityKey(rsa);
Run Code Online (Sandbox Code Playgroud)

希望对将来的人有所帮助。