c# Как проверить подпись JWT?
У меня есть токен, файл, содержащий открытый ключ, и я хочу проверить подпись. Я попытался проверить подпись на основе этой.
однако decodedCrypto и decodedSignature не совпадают.
вот мой код:
public static string Decode(string token, string key, bool verify)
    {
        var parts = token.Split('.');
        var header = parts[0];
        var payload = parts[1];
        byte[] crypto = Base64UrlDecode(parts[2]);
        var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
        var headerData = JObject.Parse(headerJson);
        var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
        var payloadData = JObject.Parse(payloadJson);
        if (verify)
        {
            var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var algorithm = (string)headerData["alg"];
            var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
            var decodedCrypto = Convert.ToBase64String(crypto);
            var decodedSignature = Convert.ToBase64String(signature);
            if (decodedCrypto != decodedSignature)
            {
                throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
            }
        }
        return payloadData.ToString();
    }
Я уверен, что подписи маркера. Я пытаюсь проверить на https://jwt.io/ и он показал, что подпись проверена. Так что проблема в алгоритме кодирования, декодирования.
Is есть кто может решить эту проблему? Алгоритм RS256
4 ответов
Я, наконец, получил разрешение от моего коллеги.
для тех у кого такая же проблема, попробуйте мой код:
public static string Decode(string token, string key, bool verify = true)
        {
            string[] parts = token.Split('.');
            string header = parts[0];
            string payload = parts[1];
            byte[] crypto = Base64UrlDecode(parts[2]);
            string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
            JObject headerData = JObject.Parse(headerJson);
            string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
            JObject payloadData = JObject.Parse(payloadJson);
            if (verify)
            {
                var keyBytes = Convert.FromBase64String(key); // your key here
                AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
                RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
                RSAParameters rsaParameters = new RSAParameters();
                rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
                rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(rsaParameters);
                SHA256 sha256 = SHA256.Create();
                byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));
                RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
                rsaDeformatter.SetHashAlgorithm("SHA256");
                if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
                    throw new ApplicationException(string.Format("Invalid signature"));
            }
            return payloadData.ToString();
        }
это работает для меня. Алгоритм RS256.
Я знаю, что это старый нить, но я мог бы recommended использовать библиотека вместо того, чтобы писать самостоятельно. У него есть хорошая документация для начала. Я использую его без каких-либо проблем.
Как насчет использования JwtSecurityTokenHandler?
это может выглядеть примерно так:
public bool ValidateToken(string token, byte[] secret)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var validationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningToken = new BinarySecretSecurityToken(secret)
    };
    SecurityToken validatedToken;
    try
    {
        tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
    }
    catch (Exception)
    {
       return false;
    }
    return validatedToken != null;
}
имейте в виду, что я не тестировал его, но мы использовали аналогичную реализацию в одном из проектов
byte[] crypto = Base64UrlDecode(parts[2]);
в этой строке вы base64 декодирования подписи часть JWT токен, но, как я знаю, эта часть не закодирована base64. Пожалуйста, попробуйте этот код. (Я прокомментировал ненужные строки)
public static string Decode(string token, string key, bool verify)
{
    var parts = token.Split('.');
    var header = parts[0];
    var payload = parts[1];
    // byte[] crypto = Base64UrlDecode(parts[2]);
    var jwtSignature = parts[2];
    var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
    var headerData = JObject.Parse(headerJson);
    var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
    var payloadData = JObject.Parse(payloadJson);
    if (verify)
    {
        var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
        var keyBytes = Encoding.UTF8.GetBytes(key);
        var algorithm = (string)headerData["alg"];
        var computedJwtSignature = Encoding.UTF8.GetString(HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign));
        // var decodedCrypto = Convert.ToBase64String(crypto);
        // var decodedSignature = Convert.ToBase64String(signature);
        if (jwtSignature != computedJwtSignature)
        {
            throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
        }
    }
    return payloadData.ToString();
}
            