C# 使用来自授权端点 (crv, x, y) 的值验证 JWT token

标签 c# jwt ecdsa jwk

我在 iframe 中的供应商站点上显示了一个网页。他们调用我的页面并在查询字符串中传递 JWT。我必须解析 jwt。

eyJraWQiOiIyMDIwLTA5LTAyVDE3OjM2OjE3LjU3MC5lYyIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJ1cm46Y2VybmVyOmlkZW50aXR5LWZlZGVyYXRpb246cmVhbG06SFdPb0lsUlgyWWRGZjkyNGJBZTZSR0l5WmtuajZrTjctY2g6cHJpbmNpcGFsOnRhNDh6OWdkNTVkNndyNW0iLCJhdWQiOiJodHRwczpcL1wvdXJsMjU4dmowai5leGVjdXRlLWFwaS51cy1lYXN0LTIuYW1hem9uYXdzLmNvbSIsImlzcyI6Imh0dHBzOlwvXC9kZXYuYmF5Y2FyZS5wYXRpZW50cG9ydGFsLnVzLTEuaGVhbHRoZWludGVudC5jb20iLCJleHAiOjE1OTkxNTQ1MTYsImlhdCI6MTU5OTE1MzkxNiwic2lkIjoiZGUwNmJhNmUtYjQyYy00ZmY5LWI4MmQtYmM4NjY0ODJmODU4In0.6Ru5Lyd1Zq016uv84pP-GjSuz6koVNipa_cd939eF21-5N2_A0Nj3I6AkDhuHrE870WzyTiCmZfkIjMOFZkRCA

我想通过从 https://authorizion.x.com/jwk 中提取值来验证签名.我得到的值如下所示:

{
   "keys":[
      {
         "kty":"EC",
         "crv":"P-256",
         "kid":"2020-09-04T18:16:04.934.ec",
         "x":"82WEbXbnfGC1kmMfjJch6gFJRp7hEp08gzZQdBLLFIk",
         "y":"ytkPwl4IjLw8M94DzgTmdAbxjq0AmmYu9mMmxpU3eBI"
      },
      {
         "kty":"EC",
         "crv":"P-256",
         "kid":"2020-09-02T17:36:17.570.ec",
         "x":"uAfEPKELRuUVMtB0DCB5oyYWnfiV8-9zHYntvI0lsRE",
         "y":"32J6nVgeb9RLdWK21QNDHhWdOsZJbxvyEq2n0IOvLtQ"
      },
      {
         "kty":"EC",
         "crv":"P-256",
         "kid":"2020-08-31T17:36:17.359.ec",
         "x":"HsxFY2vihycZgYnkSTLDHJ0Cagr2nUcZTbf2yQKPS6A",
         "y":"4kLClPGM0TG_gCUlBKkYdXrlLFVasPxQ2UOvwSBKyt0"
      }
   ]
}

我根据 JWT header 中的 kid 值选择 key 。如何根据 crv、x 和 y 值验证签名?我似乎需要公共(public)或私有(private)证书,但我没有。

我还能补充什么。它使用 ECDSA p-256 加密。在 jwt.io 上面有一个 Json Web Token,我得到以下值,

标题

{
  "kid": "2020-09-02T17:36:17.570.ec",
  "typ": "JWT",
  "alg": "ES256"
}

有效负载

{
  "sub": "urn:cerner:identity-federation:realm:HWOoIlRX2YdFf924bAe6RGIyZknj6kN7-ch:principal:ta48z9gd55d6wr5m",
  "aud": "https://url258vj0j.execute-api.us-east-2.amazonaws.com",
  "iss": "https://dev.baycare.patientportal.us-1.healtheintent.com",
  "exp": 1599154516,
  "iat": 1599153916,
  "sid": "de06ba6e-b42c-4ff9-b82d-bc866482f858"
}

签名

6Ru5Lyd1Zq016uv84pP-GjSuz6koVNipa_cd939eF21-5N2_A0Nj3I6AkDhuHrE870WzyTiCmZfkIjMOFZkRCA

我包含了与 JWT 匹配的 Java Web key 集。

最佳答案

这是一个基于 Jose 的非常简短的解决方案.

基本上您需要从给定的 URL 读取 JWKS,选择具有匹配 key ID (kid) 的正确 JWK,根据给定创建一个 ECJWKey, Base64 编码,xy 参数,然后使用该 key 验证 JWT:

以下源代码只是流程的简短说明, key 是硬编码的,不是从 JWKS 端点读取的。

using Jose;
using System;
using System.Security.Cryptography;

namespace JWKValiadation
{
    public class ECJWKey
    {
        public string kty { get; set; }
        public string crv { get; set; }
        public string kid { get; set; }
        public string x { get; set; }
        public string y { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ECJWKey ecjwkkey = new ECJWKey
            {
                kty = "EC",
                crv = "P-256",
                kid = "2020-09-02T17:36:17.570.ec",
                x = "uAfEPKELRuUVMtB0DCB5oyYWnfiV8-9zHYntvI0lsRE",
                y = "32J6nVgeb9RLdWK21QNDHhWdOsZJbxvyEq2n0IOvLtQ"
            };

            string tokenEC = "eyJraWQiOiIyMDIwLTA5LTAyVDE3OjM2OjE3LjU3MC5lYyIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJ1cm46Y2VybmVyOmlkZW50aXR5LWZlZGVyYXRpb246cmVhbG06SFdPb0lsUlgyWWRGZjkyNGJBZTZSR0l5WmtuajZrTjctY2g6cHJpbmNpcGFsOnRhNDh6OWdkNTVkNndyNW0iLCJhdWQiOiJodHRwczpcL1wvdXJsMjU4dmowai5leGVjdXRlLWFwaS51cy1lYXN0LTIuYW1hem9uYXdzLmNvbSIsImlzcyI6Imh0dHBzOlwvXC9kZXYuYmF5Y2FyZS5wYXRpZW50cG9ydGFsLnVzLTEuaGVhbHRoZWludGVudC5jb20iLCJleHAiOjE1OTkxNTQ1MTYsImlhdCI6MTU5OTE1MzkxNiwic2lkIjoiZGUwNmJhNmUtYjQyYy00ZmY5LWI4MmQtYmM4NjY0ODJmODU4In0.6Ru5Lyd1Zq016uv84pP-GjSuz6koVNipa_cd939eF21-5N2_A0Nj3I6AkDhuHrE870WzyTiCmZfkIjMOFZkRCA";

            // first read the header to get the kid
            var headers = Jose.JWT.Headers(tokenEC);
            if(headers.TryGetValue("kid", out var keyId))
            {
                // in a real application you would need the kid 
                // to select the right key from the JKWS
                Console.WriteLine(keyId);
            }

            // create the key based on the parameters from the JWK
            ECDsa eckey = ECDsa.Create(new ECParameters
            {
                Curve = ECCurve.NamedCurves.nistP256,
                Q = new ECPoint
                {
                    X = Base64Url.Decode(ecjwkkey.x),
                    Y = Base64Url.Decode(ecjwkkey.y)
                }
            });
            
            // verify and decode the token
            string payload = Jose.JWT.Decode(tokenEC, eckey);
            Console.WriteLine(payload);
        }
    }
}

关于C# 使用来自授权端点 (crv, x, y) 的值验证 JWT token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63741293/

相关文章:

c# - 以编程方式通过 C# 代码格式化 Html 代码(如 Visual Studio 中的 Ctrl + E + D)

c# - 具有 Owin JWT 身份的 MVC

android - 如何使用 JWT token 发送 HTTP 请求以从 android 中的 cookie 存储进行身份验证

ssl - ECDSA 如何用于 key 交换?

ssl - 如何在没有可导出私钥的情况下进行 ECDHE 握手

c# - System.Net.CookieException -- ...超出配置的最大大小,即 '4096'

c# - Cache-Control HTTP header 可以正常工作

c# - WCF SOAP 服务为 HTTPS 终结点返回 404 Not Found

python - 使用 JWK/JWT 进行用户身份验证的 token 验证失败

c++ - ECDSA 使用 OpenSSL 签名,使用 Crypto++ 验证