首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用SubtleCrypto验证azure活动目录令牌

使用SubtleCrypto验证azure活动目录令牌
EN

Stack Overflow用户
提问于 2022-02-05 22:41:20
回答 1查看 71关注 0票数 1

我正在尝试使用博士中描述的流来验证azure active目录ID和访问令牌。我是在浏览器里做的。我知道在前面做是没有意义的。我还是想知道怎么做。只是出于好奇。

https://jwt.io/上也有类似的地方。它是用来调试令牌的。它可以判断签名是否有效。

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

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

代码语言:javascript
复制
{
  "typ": "JWT",
  "nonce": "<redacted>",
  "alg": "RS256",
  "x5t": "<redacted>",
  "kid": "<redacted>"
}

匹配的JWK看起来像这样。

代码语言:javascript
复制
{
  "kty": "RSA",
  "use": "sig",
  "kid": "<redacted>",
  "x5t": "<redacted>",
  "n": "<redacted>",
  "e": "<redacted>",
  "x5c": ["<redacted>"]
}

我创建了这个函数来获得JWK,它使用索赔中的发行者URL和标头中的kid属性,并最终验证签名。crypto.subtle.verify总是返回false。

代码语言:javascript
复制
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
  };
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-06 00:45:15

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

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

代码语言:javascript
复制
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;
}

通过这一更改,验证是成功的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71002791

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档