質問

I need to secure my web-token with signing and encryption. I wrote the next lines of code:

var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
      Subject = new ClaimsIdentity(new[]
         {
             new Claim(ClaimTypes.Name, owner.Name),
             new Claim(ClaimTypes.Role, owner.RoleClaimType),
             new Claim("custom claim type", "custom content")
         }),
      TokenIssuerName = "self",
      AppliesToAddress = "http://www.example.com",
      Lifetime = new Lifetime(now, now.AddSeconds(60 * 3)),
      EncryptingCredentials = new X509EncryptingCredentials(new X509Certificate2(cert)),
      SigningCredentials = new X509SigningCredentials(cert1)
};
var token = (JwtSecurityToken)tokenHandler.CreateToken(tokenDescriptor);            
var tokenString = tokenHandler.WriteToken(token);

So, I am using some certificates, generated with makecert.exe. Then I read token string with another JwtSecurityTokenHandler:

var tokenHandlerDecr = new JwtSecurityTokenHandler();
var tok = tokenHandlerDecr.ReadToken(tokenString);

And token content is not encrypted (I can see json in tok variable under debugger). What am I doing wrong? How to encrypt token data?

役に立ちましたか?

解決 3

My understanding is that Microsoft's JWT implementation doesn't currently support encryption (only signing).

他のヒント

I know this an old post, but I am adding my answer in case if someone is still searching for the answer.

This issue is addressed in Microsoft.IdentityModel.Tokens version 5.1.3. There is an overloaded method available in the CreateJwtSecurityToken function which accepts the encrypting credentials to encrypt the token.

If the receiver does not validate the signature and tries to read JWT as is then the claims are empty. Following is the code snippet:

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

const string sec = "ProEMLh5e_qnzdNUQrqdHPgp";
const string sec1 = "ProEMLh5e_qnzdNU";
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec));
var securityKey1 = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec1)); 

var signingCredentials = new SigningCredentials(
    securityKey,
    SecurityAlgorithms.HmacSha512);

List<Claim> claims = new List<Claim>()
{
    new Claim("sub", "test"),
};

var ep = new EncryptingCredentials(
    securityKey1,
    SecurityAlgorithms.Aes128KW,
    SecurityAlgorithms.Aes128CbcHmacSha256);

var handler = new JwtSecurityTokenHandler();

var jwtSecurityToken = handler.CreateJwtSecurityToken(
    "issuer",
    "Audience",
    new ClaimsIdentity(claims),
    DateTime.Now,
    DateTime.Now.AddHours(1),
    DateTime.Now,
    signingCredentials,
    ep);


string tokenString = handler.WriteToken(jwtSecurityToken);

// Id someone tries to view the JWT without validating/decrypting the token,
// then no claims are retrieved and the token is safe guarded.
var jwt = new JwtSecurityToken(tokenString);

And here is the code to validate/decrypt the token:

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

const string sec = "ProEMLh5e_qnzdNUQrqdHPgp";
const string sec1 = "ProEMLh5e_qnzdNU";
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec));
var securityKey1 = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec1));

// This is the input JWT which we want to validate.
string tokenString = string.Empty;

// If we retrieve the token without decrypting the claims, we won't get any claims
// DO not use this jwt variable
var jwt = new JwtSecurityToken(tokenString);

// Verification
var tokenValidationParameters = new TokenValidationParameters()
{
    ValidAudiences = new string[]
    {
        "536481524875-glk7nibpj1q9c4184d4n3gittrt8q3mn.apps.googleusercontent.com"
    },
    ValidIssuers = new string[]
    {
        "https://accounts.google.com"
    },
    IssuerSigningKey = securityKey,
    // This is the decryption key
    TokenDecryptionKey = securityKey1
};

SecurityToken validatedToken;
var handler = new JwtSecurityTokenHandler();

handler.ValidateToken(tokenString, tokenValidationParameters, out validatedToken);

Try the following example

Updated Jul-2019: .NET Core, Asp.net Core

1.Create JWT

private string CreateJwt(string sub, string jti, string issuer, string audience)
{
    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, sub),
        new Claim(JwtRegisteredClaimNames.Jti, jti),
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS"));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    var encryptingCredentials = new EncryptingCredentials(key, JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes256CbcHmacSha512);

    var jwtSecurityToken = new JwtSecurityTokenHandler().CreateJwtSecurityToken(
        issuer,
        audience,
        new ClaimsIdentity(claims),
        null,
        expires: DateTime.UtcNow.AddMinutes(5),
        null,
        signingCredentials: creds,
        encryptingCredentials: encryptingCredentials
        );
    var encryptedJWT = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

    return encryptedJWT;
}

2.Add to ConfigureServices(IServiceCollection services) in Startup.cs

    services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,

        ValidIssuer = (string)Configuration.GetSection("JwtToken").GetValue(typeof(string), "Issuer"),
        ValidAudience = (string)Configuration.GetSection("JwtToken").GetValue(typeof(string), "Audience"),
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS")),
        TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS")),
        ClockSkew = TimeSpan.FromMinutes(0),
    };
});

Hung Quach's answer worked just fine for .NET 5 on Blazor for me. Although I changed it a bit to for my style.

   var claims = new List<Claim>()
            {
                new Claim(ClaimTypes.Name,userRequestDTO.Email)
            };
            var secret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_APISettings.SecretKey));
            var signingCredentials = new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
            var encryptionCredentials = new EncryptingCredentials(secret, JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes256CbcHmacSha512);
            var tokenOptions = new JwtSecurityTokenHandler().CreateJwtSecurityToken(new SecurityTokenDescriptor()
            {
                Audience= _APISettings.ValidAudience,
                Issuer= _APISettings.ValidIssuer,
                Subject= new ClaimsIdentity(claims),
                Expires= DateTime.Now.AddMinutes(10),
                EncryptingCredentials= encryptionCredentials,
                SigningCredentials = signingCredentials
            });

            return new JwtSecurityTokenHandler().WriteToken(tokenOptions);

then I am reading the token as follows :

 JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
                var secret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_APISettings.SecretKey));
                var signingCredentials = new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);

                tokenHandler.ValidateToken(tokenOTP,new TokenValidationParameters
                {
                    ValidIssuer = _APISettings.ValidIssuer,
                    ValidAudience = _APISettings.ValidAudience,
                    ValidateIssuerSigningKey=true,
                    ValidateLifetime = true,
                    RequireExpirationTime = true,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    IssuerSigningKey= secret,
                    TokenDecryptionKey=secret,
                    ClockSkew = TimeSpan.Zero
                },out SecurityToken validatedToken);
                var jwtToken = (JwtSecurityToken)validatedToken;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top