web-dev-qa-db-ja.com

c#署名JWTを検証する方法は?

トークン、公開キーを含むファイルがあり、署名を確認したい。 this に基づいて署名を検証しようとしました。

ただし、decodedCryptoとdecodeSignatureは一致しません。

ここに私のコードがあります:

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/ で検証しようとすると、署名が検証されたことが示されました。したがって、問題はエンコード、デコードするアルゴリズムです。

この問題を解決できる人はいますか?アルゴリズムはRS256です

enter image description here

12
anhtv13

私は同僚から最終的に解決策を得ました。

同じ問題を抱えている人のために、私のコードを試してください:

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です。

11
anhtv13

私はこれが古いスレッドであることを知っていますが、recommendedを使用することができますこのライブラリ自分で。開始するのに役立つドキュメントがいくつかあります。問題なく使用しています。

6
Coder Absolute

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;
}

私はそれをテストしていませんが、プロジェクトの1つで同様の実装を使用したことに注意してください

5
Helikaon

byte[] crypto = Base64UrlDecode(parts[2]);

この行では、JWTトークンの署名部分をbase64でデコードしていますが、私が知っているように、この部分は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();
}
0
Aram Kocharyan