【问题标题】:verify azure active directory token using SubtleCrypto使用 SubtleCrypto 验证 azure 活动目录令牌
【发布时间】:2022-02-06 08:45:15
【问题描述】:

我正在尝试使用ms docs 中描述的流程来验证 azure 活动目录 ID 和访问令牌。我正在浏览器中执行此操作。我知道在前端这样做是没有意义的。我还是想知道怎么做。只是出于好奇。

https://jwt.io/ 上有类似的东西。它旨在调试令牌。它可以判断签名是否有效。

在我的代码中,验证总是失败。我不确定在这种情况下我是否正确使用了SubtleCrypto。我也不确定我是否为其功能选择了正确的参数,比如算法。

访问令牌的标头看起来总是这样,使用 RS256。

{
  "typ": "JWT",
  "nonce": "<redacted>",
  "alg": "RS256",
  "x5t": "<redacted>",
  "kid": "<redacted>"
}

匹配的 JWK 如下所示。

{
  "kty": "RSA",
  "use": "sig",
  "kid": "<redacted>",
  "x5t": "<redacted>",
  "n": "<redacted>",
  "e": "<redacted>",
  "x5c": ["<redacted>"]
}

我创建了这个函数来使用声明中的颁发者 URL 和标头中的孩子属性获取 JWK,并最终验证签名。 crypto.subtle.verify 总是返回 false。

async function verifyToken(rawToken) {
  // parse the token into parts
  const [encodedHeaders, encodedClaims, signature] = rawToken.split(".");
  const header = JSON.parse(atob(encodedHeaders));
  const claims = JSON.parse(atob(encodedClaims));

  // get the openid config using the issuer url
  const issuer_url = claims.iss.endsWith("/") ? claims.iss : claims.iss + "/";
  const openIdConfiguration = await (
    await fetch(`${issuer_url}.well-known/openid-configuration`)
  ).json();

  // get the jwk list
  const jwkList = await (
    await fetch(openIdConfiguration.jwks_uri)
  ).json();

  // find the jwk for the kid in the token header
  const matchedKey = jwkList.keys.find(k => k.kid === header.kid)

  // return early if no jwk is found
  if (!matchedKey) return {
    rawToken,
    header,
    claims,
    signature,
    openIdConfiguration,
    jwkList,
  };
 
  // import the jwk into a a crypto key
  const pubkey = await crypto.subtle.importKey(
    "jwk",
    matchedKey,
    { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
    true,
    ["verify"],
  );

  // verify the signature
  const verified = await crypto.subtle.verify(
    { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
    pubkey,
    new TextEncoder().encode(signature),
    new TextEncoder().encode(encodedHeaders + "." + encodedClaims),
  );

  // return the results
  return {
    rawToken,
    header,
    claims,
    signature,
    openIdConfiguration,
    jwkList,
    matchedKey,
    verified
  };
};

【问题讨论】:

    标签: javascript azure-active-directory jwt cryptography


    【解决方案1】:

    JWT 的三个部分都是 Base64url 编码的,因此需要对签名进行 Base64url 解码(而不是 UTF8 编码)。 IE。 new TextEncoder().encode(signature) 行必须相应替换。

    以下代码的示例数据取自jwt.io for RS256:

    const rawToken = `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc4TSMb4bXP3l3YlNWACwyXPGffz5aXHc6lty1Y2t4SWRqGteragsVdZufDn5BlnJl9pdR_kdVFUsra2rWKEofkZeIC4yWytE58sMIihvo9H1ScmmVwBcQP6XETqYd0aSHp1gOa9RdUPDvoXQ5oqygTqVtxaDr6wUFKrKItgBMzWIdNZ6y7O9E0DhEPTbE9rfBo6KTFsHAZnMg4k68CDp2woYIaXbmYTWcvbzIuHO7_37GT79XdIwkm95QJ7hYC9RiwrV7mesbY4PAahERJawntho0my942XheVLmGwLMBkQ`;
    
    const [encodedHeaders, encodedClaims, signature] = rawToken.split(".");
    
    const matchedKey = 
    {
    "kty":"RSA",
    "e":"AQAB",
    "kid":"fa05e6ef-ec59-45b4-ba43-51b8293f7f79",
    "n":"u1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0_IzW7yWR7QkrmBL7jTKEn5u-qKhbwKfBstIs-bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW_VDL5AaWTg0nLVkjRo9z-40RQzuVaE8AkAFmxZzow3x-VJYKdjykkJ0iT9wCS0DRTXu269V264Vf_3jvredZiKRkgwlL9xNAwxXFg0x_XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC-9aGVd-Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmw"
    };
    
    (async () => {
    
        const pubkey = await crypto.subtle.importKey(
            "jwk",
            matchedKey,
            { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
            true,
            ["verify"],
        );
      
        // verify the signature
        const verified = await crypto.subtle.verify(
            { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
            pubkey,
            new base64url_decode(signature),
            new TextEncoder().encode(encodedHeaders + "." + encodedClaims),
        );
      
        console.log("Verification: ", verified);
      
    })();
    
    // Helper for Base64url encoding, from: https://thewoods.blog/base64url/
    function base64url_decode(value) {
        const m = value.length % 4;
        return Uint8Array.from(atob(
            value.replace(/-/g, '+')
                .replace(/_/g, '/')
                .padEnd(value.length + (m === 0 ? 0 : 4 - m), '=')
        ), c => c.charCodeAt(0)).buffer;
    }

    通过此更改,验证成功。

    【讨论】:

      猜你喜欢
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-17
      • 1970-01-01
      • 2015-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多