Принудительное промежуточное программное обеспечение аутентификации принимает только зашифрованные токены - PullRequest
0 голосов
/ 27 ноября 2018

Согласно этому вопросу , я использую фрагмент ниже, чтобы подписать и зашифровать JWToken.

var claims = new Claim[] { new SomeClaimes() };
var scKey = Encoding.UTF8.GetBytes("SOME KEY");
var ecKeyTemp = Encoding.UTF8.GetBytes("SOME OTHER KEY");

byte[] ecKey = new byte[256 / 8];
Array.Copy(ecKeyTemp, ecKey, 256 / 8);

var tokenDescriptor = new SecurityTokenDescriptor {
    Subject = new ClaimsIdentity(claims),
    SigningCredentials = new SigningCredentials(
        new SymmetricSecurityKey(
            scKey),
            SecurityAlgorithms.HmacSha512),
    EncryptingCredentials = new EncryptingCredentials(
        new SymmetricSecurityKey(
            ecKey),
            SecurityAlgorithms.Aes256KW,
            SecurityAlgorithms.Aes256CbcHmacSha512), 
    Issuer = "My Jwt Issuer",
    Audience = "My Jwt Audience",
    IssuedAt = DateTime.UtcNow,
    Expires = DateTime.Now.AddDays(7),
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
var jwt = tokenHandler.WriteToken(token);

А вот моя регистрация службы:

services
.AddAuthentication(o => {
    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg => {
    cfg.RequireHttpsMetadata = false;
    cfg.SaveToken = true;
    cfg.TokenValidationParameters = new TokenValidationParameters {
        ValidIssuer = "My Jwt Issuer",
        ValidAudience = "My Jwt Audience",
        IssuerSigningKey = new SymmetricSecurityKey(SameKeyAsGenerating)),
        TokenDecryptionKey = new SymmetricSecurityKey(SameKeyAsGenerating),
        ClockSkew = TimeSpan.Zero, 
        RequireSignedTokens = true,
        RequireExpirationTime = true,
        SaveSigninToken = true,
        ValidateActor = true,
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidateIssuerSigningKey = true,
        ValidateLifetime = true,
        ValidateTokenReplay = true,
    };
});

Проблема в том, что уровень аутентификации аутентифицирует как зашифрованный, так и незашифрованный токен как авторизованный.Я имею в виду, что когда я создаю токен без EncryptingCredentials (просто подписанный токен, а не зашифрованный), токен остается действительным и запрос авторизуется.Вопрос в том, как заставить слой аутентификации принимать только подписанные зашифрованные токены и отклонять только подписанные незашифрованные токены?

ОБНОВЛЕНИЕ: Решение:

Спасибона ответ Sellotape , я реализовал это JwtEncryptedSecurityTokenHandler:

public class JwtEncryptedSecurityTokenHandler : JwtSecurityTokenHandler {

    [DebuggerStepThrough]
    public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken) {
        if (string.IsNullOrWhiteSpace(token))
            throw new ArgumentNullException(nameof (token));

        if (validationParameters == null)
            throw new ArgumentNullException(nameof (validationParameters));

        if (token.Length > MaximumTokenSizeInBytes)
            throw new ArgumentException(
                $"IDX10209: token has length: '{token.Length}' which is larger than the MaximumTokenSizeInBytes: '{MaximumTokenSizeInBytes}'.");

        var strArray = token.Split(new[] { '.' }, 6);
        if (strArray.Length == 5)
            return base.ValidateToken(token, validationParameters, out validatedToken);

        throw new SecurityTokenDecryptionFailedException();
    }
}

И использовал новый обработчик в Startup.ConfigureServices():

.AddJwtBearer(cfg => {
    cfg.RequireHttpsMetadata = false;
    // other configurations...
    cfg.SecurityTokenValidators.Clear();
    cfg.SecurityTokenValidators.Add(new JwtEncryptedSecurityTokenHandler());
});

Для получения дополнительной информации см.принятый ответ.

1 Ответ

0 голосов
/ 27 ноября 2018

Я уверен, что есть несколько способов сделать это, но как насчет:

  • Реализация ISecurityTokenValidator, вероятно, наследуемая от SecurityTokenHandler;необходимые переопределения довольно просты и могут быть скопированы из JwtSecurityTokenHandler.Переопределите ValidateToken() и выбросьте, если JWT не зашифрован **.

  • Добавьте новый обработчик / валидатор в действии AddJwtBearer() configure-options: cfg.SecurityTokenValidators.Add(new RequireEncryptedTokenHandler());


** Если вы посмотрите на источник для JwtSecurityTokenHandler.ValidateToken() (точно не знаю, какую версию вы используете, но я думаю, что сообщение то же самое), онокажется, что «зашифровано» просто определяется как «имеет 5 частей», что должно быть легко внедрить (скопировать / вставить) в ваш новый обработчик.

...