将 SymmetricSecurityKey 交换为 JWT 的 AsymmetricSecurityKey
Swapping SymmetricSecurityKey for AsymmetricSecurityKey for JWT
渗透测试建议我们更改 JWT 实现以使用非对称签名而不是对称签名,后者运行良好。
创建对称令牌的当前(完美工作)代码如下:(灵感最初来自 How to encrypt JWT security token?)
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);
}
}
检查任何 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) { });
}
我已经在网上尝试了很多示例并阅读了很多帖子,但还没有任何工作,每个都有一大堆不同的问题。可能我已经关闭的是以下一些示例:
下面是一个似乎在创建代码时起作用的示例,但在将令牌与传入的 API 调用进行比较时,这不会起作用。
RSA _rsaa;
_rsaa = new RSACryptoServiceProvider(2048);
var r = _rsaa.ExportParameters(true);
SigningCredentials signingCredentials3a = new SigningCredentials(new RsaSecurityKey(_rsaa), SecurityAlgorithms.RsaSha256Signature);
最后,下面的选项感觉正确,但由于字符串中包含加密密钥内容,出现 'Bad Version of provider.' 错误。
byte[] Key256Bytes = Encoding.ASCII.GetBytes(Key256);
rsa.ImportCspBlob(Key256Bytes);
SigningCredentials signingCredentials5 = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256Signature);
我在使用各种选项时遇到困难。
找到解决方案,将上面的转换为非对称加密,交换:
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
和
var rsa = new RSACryptoServiceProvider();
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));
SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha512Signature);
加密密钥是使用以下生成的。
var rsa = new RSACryptoServiceProvider(2048);
var key = Convert.ToBase64String(rsa.ExportCspBlob(true));
然后在检查传入的JWT时:
SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
有
var rsa = new RSACryptoServiceProvider();
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));
RsaSecurityKey SecurityKey = new RsaSecurityKey(rsa);
希望对以后的人有所帮助。
渗透测试建议我们更改 JWT 实现以使用非对称签名而不是对称签名,后者运行良好。
创建对称令牌的当前(完美工作)代码如下:(灵感最初来自 How to encrypt JWT security token?)
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);
}
}
检查任何 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) { });
}
我已经在网上尝试了很多示例并阅读了很多帖子,但还没有任何工作,每个都有一大堆不同的问题。可能我已经关闭的是以下一些示例:
下面是一个似乎在创建代码时起作用的示例,但在将令牌与传入的 API 调用进行比较时,这不会起作用。
RSA _rsaa;
_rsaa = new RSACryptoServiceProvider(2048);
var r = _rsaa.ExportParameters(true);
SigningCredentials signingCredentials3a = new SigningCredentials(new RsaSecurityKey(_rsaa), SecurityAlgorithms.RsaSha256Signature);
最后,下面的选项感觉正确,但由于字符串中包含加密密钥内容,出现 'Bad Version of provider.' 错误。
byte[] Key256Bytes = Encoding.ASCII.GetBytes(Key256);
rsa.ImportCspBlob(Key256Bytes);
SigningCredentials signingCredentials5 = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256Signature);
我在使用各种选项时遇到困难。
找到解决方案,将上面的转换为非对称加密,交换:
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
和
var rsa = new RSACryptoServiceProvider();
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));
SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha512Signature);
加密密钥是使用以下生成的。
var rsa = new RSACryptoServiceProvider(2048);
var key = Convert.ToBase64String(rsa.ExportCspBlob(true));
然后在检查传入的JWT时:
SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(SecurityConstants.ConstSecurityEncryptionKey));
有
var rsa = new RSACryptoServiceProvider();
rsa.ImportCspBlob(Convert.FromBase64String(SecurityConstants.ConstAsyncSecurityEncryptionKey));
RsaSecurityKey SecurityKey = new RsaSecurityKey(rsa);
希望对以后的人有所帮助。