gpt4 book ai didi

digital-signature - 如何正确对 SAML2.0 AuthnRequest 进行数字签名?

转载 作者:行者123 更新时间:2023-12-04 12:53:47 40 4
gpt4 key购买 nike

我在 express/nodejs 上有一个内置的咖啡脚本 SAML2.0 单点登录系统。

我用 SSOCircle测试我的 SSO,并且可以使用 HTTP-POST 或 HTTP-REDIRECT 绑定(bind)在那里成功进行身份验证。到现在为止还挺好。

现在我需要对我的身份验证请求进行数字签名。

为此,我使用了 nodejs xml-crytpo图书馆。这导致 SAML 如下所示:

<?xml version="1.0"?>
<samlp:AuthnRequest Version="2.0" ID="_1C8A2EFA-2644-4330-9A36-2B45547ECFAF" IssueInstant="2014-10-14T16:06:27.769Z" Destination="https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/ssocircle" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>http://app.localhost</saml:Issuer>
<samlp:NameIDPolicy AllowCreate="true" />
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#_1C8A2EFA-2644-4330-9A36-2B45547ECFAF">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>m4qHiXM82TuxY31l6+QSECHEHc0=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>fps0I0Rp02qDK0BPTK7Lh+ ...</SignatureValue>
<KeyInfo>
<X509Data>MIICuDCCAaCgAwIBAgIQEVFtJk ...</X509Data>
</KeyInfo>
</Signature>
</samlp:AuthnRequest>

为简洁起见,数字签名中包含的证书信息已被删除,但它来自 pem我在本地生成的文件(自签名)。

我还更新了提供给 SSOCircle 的服务提供商元数据以包含 SAML 属性 AuthnRequestsSignedWantAssertionsSigned , 像这样:
<md:EntityDescriptor entityID="http://app.localhost" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
...
</md:SPSSODescriptor>
</md:EntityDescriptor>

发送我的 AuthnRequest没有数字签名工作正常。当我包含数字签名时,它会失败,状态码为 500和通用的“无效请求”消息。

如何正确地对我的 AuthnRequest 进行数字签名所以它对 SSOCircle 有效?

谢谢。

编辑 1 - 将证书 key 添加到 SP 元数据

按照评论中的建议,我现在添加了适当的 KeyDescriptor属性到我的 sp-metadata 以包括我的自签名证书的公钥。
<md:EntityDescriptor entityID="http://app.localhost" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509SubjectName>CN=app.localhost</ds:X509SubjectName>
<ds:X509Certificate>MIICu ... wg==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIICu ... wg==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
...
</md:EntityDescriptor>

我已经包含了两个 KeyDescriptor元素,一个指定 use = signing另一个指定 use = encryption ,虽然我认为后者是多余的(因为我在 TLS 上运行)并且会被 IdP 忽略。

这不起作用,我得到同样的错误:

Reason: The SAML Request is invalid.



编辑 2 - 自签名证书

理论 : 我不能使用自签名证书。相反,我必须使用 SSOCircle 已知并信任的证书

结果 : 这个被驳倒了。只要 sp-metadata 中包含正确的公钥,您就可以使用自签名证书。

编辑 3 - 添加正确 Transform算法

我现在更新了我的签名以指定 #enveloped-signature变换算法。
        <Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>

我还发现包含的 x509 证书公钥的正确结构如下(注意内部 X509Certificate 元素):
<KeyInfo>
<X509Data>
<X509Certificate>MIID...MMxZ</X509Certificate>
</X509Data>
</KeyInfo>

我现在正在使用 TestShib站点运行,因为这允许访问提供更详细和有用信息的 IdP 日志。

编辑 4 - 交换 SAML 元素顺序以匹配架构

根据@Hos 给出的答案(见下文),SAML 元素的顺序必须与架构匹配。因此 signature元素必须直接出现在 issuer 之后元素,像这样:
<samlp:AuthnRequest Version="2.0" ID="_782F6F1E-1B80-4D7D-B26C-AC85030D9300" IssueInstant="2014-10-28T11:45:49.412Z" Destination="https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/ssocircle" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>http://app.localhost9de83841</saml:Issuer>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#_782F6F1E-1B80-4D7D-B26C-AC85030D9300">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>pjXEtbAFMJA3hWhD/f6lxJTshTg=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>FY1...Qg==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIID...MMxZ</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<samlp:NameIDPolicy AllowCreate="true" />
</samlp:AuthnRequest>

这仍然使 SSOCircle 失败,并显示不透明的 500 错误。但是 TestShib 显示以下日志:
11:02:37.292 - DEBUG [edu.internet2.middleware.shibboleth.common.security.MetadataPKIXValidationInformationResolver:631] - Write lock over cache acquired
11:02:37.292 - DEBUG [edu.internet2.middleware.shibboleth.common.security.MetadataPKIXValidationInformationResolver:634] - Added new PKIX info to entity cache with key: [http://app.localhost9de83841,{urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor,urn:oasis:names:tc:SAML:2.0:protocol,SIGNING]
11:02:37.292 - DEBUG [edu.internet2.middleware.shibboleth.common.security.MetadataPKIXValidationInformationResolver:637] - Write lock over cache released
11:02:37.293 - WARN [edu.internet2.middleware.shibboleth.idp.profile.saml2.SSOProfileHandler:406] - Message did not meet security requirements
org.opensaml.ws.security.SecurityPolicyException: **Validation of protocol message signature failed**

当我阅读本文时,用于验证签名的公钥已从 sp-metadata 中提取:
Added new PKIX info to entity cache with key: [http://app.localhost9de83841,{urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor,urn:oasis:names:tc:SAML:2.0:protocol,SIGNING]

然而,实际验证失败了,大概是因为摘要值不匹配。这意味着 xmlcrypto 计算的摘要与 ShibTest 计算的摘要不同。这肯定只是出于以下两个原因之一:
  • xmlcrypto 和 TestShib 用于生成摘要的算法有些不同
  • 公钥不匹配。

  • 对键的仔细检查表明它们是相同的。所以这是我的代码,以防你能发现任何东西。

    备注 :此代码依赖于 nodejs xmlbuilderxml-crytpo图书馆)
    getSamlRequest:(idpUrl, requestId, next)->
    request = @xmlbuilder.create
    'samlp:AuthnRequest':
    '@xmlns:samlp':'urn:oasis:names:tc:SAML:2.0:protocol'
    '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
    '@Version': '2.0'
    '@ID': requestId
    '@IssueInstant': (new Date()).toISOString()
    '@Destination': idpUrl
    'saml:Issuer': '@@spEntityId'
    ,null
    ,headless: true
    request.comment 'insert-signature'
    request.element 'samlp:NameIDPolicy':
    '@AllowCreate': 'true'
    saml = request.end()
    #Your self-signed pem file that contains both public and private keys.
    #The public key must also be included in your sp-metadata
    certFilePath = "certs/sp-certificate.pem"
    @fs.readFile certFilePath, (err, certificate)=>
    signer = new @xmlcrypto.SignedXml()
    signer.signingKey = certificate
    signer.addReference "//*[local-name(.)='AuthnRequest']", ['http://www.w3.org/2000/09/xmldsig#enveloped-signature']
    signer.keyInfoProvider = new =>
    getKeyInfo: (key)=>
    public_key = /-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec(key)[1].replace /[\r\n|\n]/g, ''
    "<X509Data><X509Certificate>#{public_key}</X509Certificate></X509Data>"
    signer.computeSignature saml
    signature = signer.getSignatureXml()
    signed = saml.replace '<!-- insert-signature -->', signature
    return next null, signed

    编辑 5 - 请求跟踪

    下面是在与 SSOCircle 的 SAML 握手期间发出的请求的跟踪。输出由 nodejs request 生成模块与 request-debug 一起使用模块。

    我在此跟踪输出下方包含了一些说明。
    { request: 
    { debugId: 17,
    uri: 'http://localhost:8082/security/sso/subscription/dev2/096b75a2-4a55-4eec-83c8-d2509e948b07',
    method: 'GET',
    headers: { host: 'localhost:8082' } } }
    { response:
    { debugId: 17,
    headers:
    { 'transfer-encoding': 'chunked',
    'content-type': 'application/json; charset=utf-8',
    server: 'Microsoft-HTTPAPI/2.0',
    'access-control-allow-origin': '*',
    'access-control-allow-headers': 'origin, x-requested-with, accept, content-type',
    'access-control-allow-methods': 'GET, POST, PATCH, PUT, DELETE',
    date: 'Wed, 05 Nov 2014 16:55:49 GMT' },
    statusCode: 200,
    body: '{"RequestId":"_F7DDDD24-32C6-420E-A550-95872D30033B","SubscriptionName":"Develop-2","SubscriptionURL":"dev2","IdentityProviderCertificateFile":"ssocircle.cer","IdentityProviderDestinationUrl":"https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/ssocircle","SAMLBinding":"HttpPost"}' } }
    { request:
    { debugId: 18,
    uri: 'https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/ssocircle',
    method: 'POST',
    headers:
    { host: 'idp.ssocircle.com:443',
    'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
    'content-length': 3492 },
    body: 'SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBWZXJzaW9uPSIyLjAiIElEPSJfRjdEREREMjQtMzJDNi00MjBFLUE1NTAtOTU4NzJEMzAwMzNCIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMTEtMDVUMTY6NTU6NDkuODkwWiIgRGVzdGluYXRpb249Imh0dHBzOi8vaWRwLnNzb2NpcmNsZS5jb206NDQzL3Nzby9TU09QT1NUL21ldGFBbGlhcy9zc29jaXJjbGUiPjxzYW1sOklzc3Vlcj5odHRwOi8vYXBwLmxvY2FsaG9zdDlkZTgzODQxPC9zYW1sOklzc3Vlcj48U2lnbmF0dXJlIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48U2lnbmVkSW5mbz48Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgLz48U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3JzYS1zaGExIiAvPjxSZWZlcmVuY2UgVVJJPSIjX0Y3RERERDI0LTMyQzYtNDIwRS1BNTUwLTk1ODcyRDMwMDMzQiI%2BPFRyYW5zZm9ybXM%2BPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIiAvPjwvVHJhbnNmb3Jtcz48RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiIC8%2BPERpZ2VzdFZhbHVlPjBLdUtNVG1Zc29Wb1BlTXhtdDhuNml2M3RxZz08L0RpZ2VzdFZhbHVlPjwvUmVmZXJlbmNlPjwvU2lnbmVkSW5mbz48U2lnbmF0dXJlVmFsdWU%2BY1htVFJPWVBSWFZPNHpWSkxURXBBSWd0RTd1c2NsSG1QS0NFdTB0NXNzcmVYSjd1a0M4dWdGd2c4Zm1yWDZDenhib3FHNVl1enJkb2RWVVNsbU12bHZXMGpiaWtsQVBXMmtPNTcralB4TWV3UTdFdzJZdTJuRTZ2QkFhMUwxWGpsa0g0a1UrdlVWVEpFQnlsdXhOYjRQN0xoZnJTdnVrZDhWejJwbk5QTnJtY0tJZVp1LzFlZU8wWmRyRVZrdEY1REhVaFV0MEs5aFBhRXB5Z0xsYjVKYWhNZEttei9uQWk4OU04aTEyUTdrQ2hwb1UrcmhjYTQzaDBXdGk2SWI1N1lWRzgyMzE5MlNsdGR5UkZPdXl2bEJRL0FMSkdpN0hNYzRMRXVkQktOL3pxaUFpK1NZYm1ONVNuN0NucFJWbW13U3NJUElncWxCbmlrU2pIQzRQS1VBPT08L1NpZ25hdHVyZVZhbHVlPjxLZXlJbmZvPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSURnRENDQW1pZ0F3SUJBZ0lESUFTeE1BMEdDU3FHU0liM0RRRUJCUVVBTUM0eEN6QUpCZ05WQkFZVEFrUkZNUkl3RUFZRFZRUUtFd2xUVTA5RGFYSmpiR1V4Q3pBSkJnTlZCQU1UQWtOQk1CNFhEVEUwTVRBeE5qRTBOVFl3TlZvWERURTFNVEF4TmpFME5UWXdOVm93TmpFTE1Ba0dBMVVFQmhNQ1JFVXhFakFRQmdOVkJBb1RDVk5UVDBOcGNtTnNaVEVUTUJFR0ExVUVBeE1LWW1sdlpuSmhZM1JoYkRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS0Y0dDhzWVZNdHRVZkZ3eTZneFpQVjVWbWtCMDZwNXNqck5vUjUxUXZISmZFMkgyTnVTa0Nxa2paVmFwb1FRMStUVTNlelloMmxNVGNYSjU1Y0t2d0lUTlEvQWlLckxjaG4wdGxYZXFIRXhIdXBvazRGd1hqc20xSitpZTBvOUc1UDlRNTFXelRjRXYxSFRBV2Rkak9OK3Zsd3d0YndTaWRtNFBkN3hxZDdvQkhXTjJJSExQNlpGVHRPVWNpdzI1K0xtRk90V3dHdU41c1pNWDV6RDNUc216Y3ZNMFQwUzF0SVlHamhpaWNnM2UrbmhkWXhjSVNvZ1B1NjNlSWswKzM2OFU1TkhnYlJ5SVRnR2tPMFdtTU9PNDhpbFlFcWlPR1E3d3FxeTdrMzZzRGNxZXdiV1lvejFnQzBieGJBeXI1d3ZZUDdnaEVHYktSVXRWeDExZzdVQ0F3RUFBYU9CbmpDQm16QUpCZ05WSFJNRUFqQUFNQ3dHQ1dDR1NBR0crRUlCRFFRZkZoMVBjR1Z1VTFOTUlFZGxibVZ5WVhSbFpDQkRaWEowYVdacFkyRjBaVEFkQmdOVkhRNEVGZ1FVcTFyMnltMkRXb1NoYWgyRm11ekxJOWZjdDdZd1FRWURWUjBqQkRvd09LRXlwREF3TGpFTE1Ba0dBMVVFQmhNQ1JFVXhFakFRQmdOVkJBb1RDVk5UVDBOcGNtTnNaVEVMTUFrR0ExVUVBeE1DUTBHQ0FncVlNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0SUJBUUFIRW5xTlVKN2VaYkkvNmozZTNmK2tFY3BQQUs2L3dXS0hSL1k2TWt1TGZpZERPREJ4eDRPTThQL1MrNFV4QkZSYWtBNFRkWkRNbjdJT2dTZ2Z3elQ0RjFxS1cvTkJKMzRtcjdndi9Yc0gxTDdHMlBEZFdUdmdGN1N5aFpCck9rbVYyZy9KYWg2U2pBREdabGdPWGJuTTlHUjlNN1NpVDBUcmFkay90dU9Zc2pxd2NJaE40eTVwSU9MNnZlemJKQThIeWZUY1lpMGFZVXFyMGl4Qkw1WWh5VDA1Qk13SUhkdFFNNGhqNjdyRDV4ME9QcmVrcTg0MjRkL0RGWmV5QTRBNG04Z3BOL0VDTFF0NzN3ajlqMVRudjBLdmlLRGZOcWJ4NngvL1o3MnN6VVhpWldETWJrNnhvdHVOZTV6Yy9xcXdhSWxLZ2lnWDJvcGRvbU9nTU14WjwvWDUwOUNlcnRpZmljYXRlPjwvWDUwOURhdGE%2BPC9LZXlJbmZvPjwvU2lnbmF0dXJlPjxzYW1scDpOYW1lSURQb2xpY3kgQWxsb3dDcmVhdGU9InRydWUiLz48L3NhbWxwOkF1dGhuUmVxdWVzdD4%3D' } }
    { response:
    { debugId: 18,
    headers:
    { server: '"SSOCircle Web Server"',
    date: 'Wed, 05 Nov 2014 16:55:48 GMT',
    'content-type': 'text/html;charset=UTF-8',
    connection: 'close',
    'set-cookie': [Object],
    'transfer-encoding': 'chunked' },
    statusCode: 500,
    body: '\n\n\n\n<html><head><title>\n Error Page\n \n </title>\n <link href="/css/bx.css" rel="stylesheet" type="text/css" /></head>\n <body>\n <div id="myheader">\n <h1><img src="/logo.png" alt="IDPee - Put your LOGO here" height="65" width="180">&nbsp;</h1>\n </div>\n <div id="mycontent">\n <div id="mynav">\n <ul>\n \n </ul>\n </div>\n <div id="mybox">\n <p>\n \n <h2>Error occurred</h2>\n<p>\nReason: Invalid signature in Request.\n</p>\n\n \n </p>\n </div>\n \n </div>\n <div id="myfooter">\n \n Copyright &copy; SSOCircle/IDPee.com\n \n \n </div>\n </body>\n</html>\n\n\n\n' } }
    error: message=Something went wrong whilst trying to automatically log you in. Please try again., name=SSOFailure, message=An error occurred whilst processing the SSO Request., name=SSORequestFailure, message=The IdP failed to successfully process the SAMLRequest and returned an statuscode of 500., name=SamlRequestInvalid, url=http://app.localhost/security/saml2/request

    请求 debugId = 17 :这是我的客户端向我的 nodejs 代理服务器发出的调用,它启动了 SAML 握手。

    回复 debugId = 17 :从代理服务器返回给客户端的 200 OK 响应。现在,一旦 SAML 握手结束,客户端就会等待重定向。

    请求 debugId = 18 :SAMLRequest 被发布到 SSOCircle SAML 端点

    回复 debugId = 18 :来自 SSOCircle 的 500 内部服务器错误响应以及 HTML 错误页面负载。

    最佳答案

    关于 Edit2:只要 SSOCircle 包含在服务提供商的元数据中,自签名证书就足够了。

    关于 Edit3:请在 issuer 元素之后移动签名元素。请求必须符合架构:

    <sequence>
    <element ref="saml:Issuer" minOccurs="0"/>
    <element ref="ds:Signature" minOccurs="0"/>
    <element ref="samlp:Extensions" minOccurs="0"/>
    </sequence>

    关于digital-signature - 如何正确对 SAML2.0 AuthnRequest 进行数字签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26365664/

    40 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com