【问题标题】:Failing signature validation of JWT tokens from Azure AD来自 Azure AD 的 JWT 令牌的签名验证失败
【发布时间】:2020-04-21 03:44:47
【问题描述】:

通过关注this MS info about client credential grants,我得到了一个 JWT 令牌:

eyJ0eXAiOiJKV1QiLCJub25jZSI6InBOWU1CVkZKcFAxVjJ1VTFaUnM1V3NOLVhyeDhjXzhWWjU5RWxhTFZBeDAiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwiaWF0IjoxNTg0NzIwNjk3LCJuYmYiOjE1ODQ3MjA2OTcsImV4cCI6MTU4NDcyNDU5NywiYWlvIjoiNDJOZ1lIaTZxVjRxS0xoLzRteUd0UzBmb3lLWEFRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJSc2tUZXN0QXBwIiwiYXBwaWQiOiJlMjcwYmNkNC00ZDU0LTRiN2MtYWFmYy1hYjUyZWZmMjA5N2UiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwib2lkIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwic3ViIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwidGlkIjoiMDJkYWY1MGQtNGQxZS00YTk1LWEyNGEtYzk4NzA1MzQwZWMwIiwidXRpIjoiMVVxeV9PemJJMDZOSGp6VHo1Qm9BQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTg0NzE3OTU0fQ.fy2TIhXb89Ic2wuw7ysao-JzBqzpQGHD29A_X-Jrj eEXOTvO5AB75tn0G1zV69vYkg2hEMsv3Dej5pNJ82w8NETRXMEEhC6ke9-URk0uKzWJ_ZzxNrL9I1eD8N4UUhqXeJifYE9gatDRqSfFmEn5eQbRVgEegJMmpqb7DMeUH8pOkTZLKzFHjSmJATx2eQBkW1PiMEL5u-QuIiZohObxficQ8PvK-IgE2V_LcTuVnEVXBrgYfZllPesQTP9-fjV_iGnM5gwcnVhwqNdpk9Ws-Vz2XDgRRCDu604IbYv3SvA9JhbKByo0CPreMfhqjrP5l_0Rm_bJeGj9iJrql5Jj3w

当我简单地将其复制粘贴到jwt.io 时,令牌已正确解码,但其签名验证失败。 所以怀疑jwt.io不能正常工作,想自己验证一下token。

令牌的标头:

{
  "typ": "JWT",
  "nonce": "pNYMBVFJpP1V2uU1ZRs5WsN-Xrx8c_8VZ59ElaLVAx0",
  "alg": "RS256",
  "x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
  "kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"
}

根据this description where the Azure public keys/certificates are available,我获取了它们并且带有 kid=YMELHT0gvb0mxoSDoYfomjqfjYU 的密钥在那里:

{
     "kty":"RSA",
     "use":"sig",
     "kid":"YMELHT0gvb0mxoSDoYfomjqfjYU",
     "x5t":"YMELHT0gvb0mxoSDoYfomjqfjYU",
     "n":"ni9SAyu9EsltQlV7Jo3wMUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2_UmnVBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm_4xzJ3F0yF0Y_aRBMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY_vUGt_5-sPo6BXoV7oov4Ps6jeyUdRKtqVZSp5_kzz16kPh1Ng_2tn4vpQimNbHRralq8rNM_gOLPAar6v7mL_qsqpgx-48e5ENFxikbB-NzAmLll1QSkzciu2rCjFGH4j_-bCHr7FxUNDL_E0vMFVDFw8SUlYMgQ",
     "e":"AQAB",
     "x5c":[
        "MIIDBTCCAe2gAwIBAgIQG4GFMDOjD7lKSdsgshqQ/DANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIwMDIwNTAwMDAwMFoXDTI1MDIwNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4vUgMrvRLJbUJVeyaN8DFL3KWG+Jpnx81eCLA2ejULyY7UCbobH6ohvOlZ7THe+keOJAppHzBr7UEQNv1Jp1QUki8UCr3BlKjaHR+2GjGDk5h5WzkqFaYtzsdsI+nFr4Wk05v+McydxdMhdGP2kQTMUgiMC7950zETXu+JOM3QZ4S+5OTmzmP71Brf+frD6OgV6Fe6KL+D7Oo3slHUSralWUqef5M89epD4dTYP9rZ+L6UIpjWx0a2pavKzTP4DizwGq+r+5i/6rKqYMfuPHuRDRcYpGwfjcwJi5ZdUEpM3IrtqwoxRh+I//mwh6+xcVDQy/xNLzBVQxcPElJWDIECAwEAAaMhMB8wHQYDVR0OBBYEFHssLV3w8SFEdZk03/TJwDfWQ6mRMA0GCSqGSIb3DQEBCwUAA4IBAQAh9iGtY+wKAMrYYLCU8uRZnUY9f+s936HhZdnJfVCuJM7y3fIbzvPO0T0dMHLz++ba0rkptoe+HjZaNA7vVwzdEtAdNff0wFef470sb+kxPi64PZK/IhtqBEwEvy090ZwGsZqM/Ut9QxFH21/t/wcz0wUBc6QGGxgWr1T/Qfzlemnz5DxuHaKQdiafz6yrwGyVjmaRkjMqeqhQy3J0nNoJNbofopSnnGH0g5IWBJBJPBk7k8RaliY0i+GwTliCgiI59ZPt1dS1+EXfNS06v1+TjTe1tPHyGot03i+iIA3WJk3REgT14y7Rhl94htzmMFmrlGNioXlfLFx9fDJQkJfz"
     ],
     "issuer":"https://login.microsoftonline.com/{tenantid}/v2.0"
}

接下来我从证书中提取公钥:

openssl x509 -in ms_signing_cert4.pem -pubkey -noout

-----开始公钥----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni9SAyu9EsltQlV7Jo3w MUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2/Umn VBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm/4xzJ3F0yF0Y/aR BMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY/vUGt/5+sPo6BXoV7oov4Ps6jeyUdRK tqVZSp5/kzz16kPh1Ng/2tn4vpQimNbHRralq8rNM/gOLPAar6v7mL/qsqpgx+48 e5ENFxikbB+NzAmLll1QSkzciu2rCjFGH4j/+bCHr7FxUNDL/E0vMFVDFw8SUlYM gQIDAQAB -----结束公钥-----

最后我使用 Python PyJWT 库来验证签名:

import jwt

token = 'eyJ0eXAiOiJKV1QiLCJub25jZSI6InBOWU1CVkZKcFAxVjJ1VTFaUnM1V3NOLVhyeDhjXzhWWjU5RWxhTFZBeDAiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwiaWF0IjoxNTg0NzIwNjk3LCJuYmYiOjE1ODQ3MjA2OTcsImV4cCI6MTU4NDcyNDU5NywiYWlvIjoiNDJOZ1lIaTZxVjRxS0xoLzRteUd0UzBmb3lLWEFRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJSc2tUZXN0QXBwIiwiYXBwaWQiOiJlMjcwYmNkNC00ZDU0LTRiN2MtYWFmYy1hYjUyZWZmMjA5N2UiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwib2lkIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwic3ViIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwidGlkIjoiMDJkYWY1MGQtNGQxZS00YTk1LWEyNGEtYzk4NzA1MzQwZWMwIiwidXRpIjoiMVVxeV9PemJJMDZOSGp6VHo1Qm9BQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTg0NzE3OTU0fQ.fy2TIhXb89Ic2wuw7ysao-JzBqzpQGHD29A_X-JrjeEXOTvO5AB75tn0G1zV69vYkg2hEMsv3Dej5pNJ82w8NETRXMEEhC6ke9-URk0uKzWJ_ZzxNrL9I1eD8N4UUhqXeJifYE9gatDRqSfFmEn5eQbRVgEegJMmpqb7DMeUH8pOkTZLKzFHjSmJATx2eQBkW1PiMEL5u-QuIiZohObxficQ8PvK-IgE2V_LcTuVnEVXBrgYfZllPesQTP9-fjV_iGnM5gwcnVhwqNdpk9Ws-Vz2XDgRRCDu604IbYv3SvA9JhbKByo0CPreMfhqjrP5l_0Rm_bJeGj9iJrql5Jj3w'
pub_key = b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni9SAyu9EsltQlV7Jo3w\nMUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2/Umn\nVBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm/4xzJ3F0yF0Y/aR\nBMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY/vUGt/5+sPo6BXoV7oov4Ps6jeyUdRK\ntqVZSp5/kzz16kPh1Ng/2tn4vpQimNbHRralq8rNM/gOLPAar6v7mL/qsqpgx+48\ne5ENFxikbB+NzAmLll1QSkzciu2rCjFGH4j/+bCHr7FxUNDL/E0vMFVDFw8SUlYM\ngQIDAQAB\n-----END PUBLIC KEY-----'

print(jwt.decode(token, pub_key, algorithms=['RS256']))

结果

jwt.exceptions.InvalidSignatureError: 签名验证失败

我尝试在我的 PC 上生成我自己的 JWT,也由 RS256 签名 - 在 jwt.io 和 PyJWT 上都通过。我在网上某处找到的示例令牌也是如此。只是无法处理 AAD 发行的令牌。

这些 AAD 令牌缺少什么? 非常感谢。

【问题讨论】:

    标签: azure jwt azure-active-directory openid-connect


    【解决方案1】:

    您的令牌是正确的。它只是图形 api 的特定标记。您将在 Jwt.Header 中看到 nonce。这意味着您需要特殊处理。正常处理会失败。

    如果您是获取 Graph 令牌的客户,请假设它是 您永远不应该查看的加密字符串 - 有时会。 我们为 Graph 使用一种特殊的令牌格式,他们知道如何验证 - 如果访问令牌不适合您,您不应该查看它们。

    查看详情here

    参考:

    Can not validate signature

    【讨论】:

    • 你能解释一下吗?令牌本身显示“alg”:“RS256”。使用非对称算法 RSA 签名。你告诉我忽略它并使用对称 HMAC。那么 MS 用来签署令牌并且我将用来验证它的密钥是什么?
    • @RadekSkokan 您对此还有其他顾虑吗?
    【解决方案2】:

    确实如此。这个 nonce 在 V2 中,是 V1 令牌的补充。 我曾经使用这个 sn-p 验证 V1:

                    var signatureKey = signatureKeyIdentifier.X509CertificateChain.First();
                    var certificate = new X509Certificate2(signatureKey.ToBytesFromBase64URLString());
                    var rsa = certificate.GetRSAPublicKey();
                    var data = string.Format("{0}.{1}", header, payload).ToBytes();
                    var isValidSignature = rsa.VerifyData(
                        data,
                        signature.ToBytesFromBase64URLString(),
                        HashAlgorithmName.SHA256,
                        RSASignaturePadding.Pkcs1);
    

    但是现在这个验证将失败。 请注意,我正在创建标题提供的证书。 随机数与签名无关,它只是一个随每个请求/令牌而变化的数字,以确保没有人重播该有效令牌。验证随机数是通过将所有随机数保存在数据库中并检查唯一性。 我认为我们需要找出计算签名的变化。他们还在使用相同的填充吗?同样的算法?

    我现在用来验证的方式是将该令牌发送到同一个活动目录以获取数据,然后 AD 将仅根据有效令牌提供数据。

    【讨论】:

      猜你喜欢
      • 2017-05-19
      • 2019-06-14
      • 2021-09-10
      • 2016-12-02
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 2021-08-05
      • 2018-12-25
      相关资源
      最近更新 更多