SAML 2.0响应含AttributeStatement时DigestValue计算问题
SAML 2.0 携带AttributeStatement时DigestValue正确计算方案
核心问题说明
你之前的计算流程忽略了XML签名规范要求的转换顺序、专属命名空间规则、空白字符约束,这是新增AttributeStatement后摘要失配的核心原因,且注意不可手动删除saml2:AttributeStatement节点,Okta签名时已经将该节点纳入计算范围,删除后必然无法匹配。
正确计算步骤
- 定位待计算的根节点:本次签名的Reference URI为
#id2725281198079267683856882,对应完整的<saml2:Assertion>节点,需要完整保留该节点的所有原始内容(除后续要删除的Signature片段)。 - 执行第一个转换(enveloped-signature规则):完整删除节点内的整个
<ds:Signature>元素及其所有子节点,清理干净删除位置的残留空白符,和原始内容的空白逻辑保持一致。 - 执行第二个转换(专属规范化exc-c14n规则):
- 遵循签名配置里的
<ec:InclusiveNamespaces PrefixList="xs"/>要求,将xs前缀的命名空间做包含处理,不可按默认专属规范化规则省略 - 严格保留原始XML的节点顺序、属性顺序、属性值引号格式,尤其不要手动删除AttributeStatement内部的
xmlns:xsi、xmlns:xs命名空间声明 - 完全保留原始内容的换行、缩进等空白字符,不要手动格式化代码调整缩进或换行,Okta生成的XML空白符会参与哈希计算
- 遵循签名配置里的
- 摘要计算:将规范化后的内容以UTF-8(无BOM)编码转二进制流,使用SHA-256算法计算哈希值,再对哈希结果做Base64编码,即可得到和IDP返回一致的DigestValue。
示例断言参考
<saml2:Assertion ID="id2725281198079267683856882" IssueInstant="2021-09-20T07:18:33.051Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" > <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" >http://www.okta.com/exk1mv3c9ke9u3tz25d7 </saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> <ds:Reference URI="#id2725281198079267683856882"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <ec:InclusiveNamespaces PrefixList="xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> <ds:DigestValue>uHowdunaQ+0tDsHrEGgJFUWwd23L08Qubp9HFS2In2Q=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>S9YQNf7t...</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIIDq... </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">allen.li@gmail.com</saml2:NameID> <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml2:SubjectConfirmationData InResponseTo="a3b3ff8jicf316993316069j03bdjfj" NotOnOrAfter="2021-09-20T07:23:33.051Z" Recipient="http://localhost:8080/saml/SSO" /> </saml2:SubjectConfirmation> </saml2:Subject> <saml2:Conditions NotBefore="2021-09-20T07:13:33.051Z" NotOnOrAfter="2021-09-20T07:23:33.051Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" > <saml2:AudienceRestriction> <saml2:Audience>http://localhost:8080/saml/metadata</saml2:Audience> </saml2:AudienceRestriction> </saml2:Conditions> <saml2:AuthnStatement AuthnInstant="2021-09-20T07:18:33.051Z" SessionIndex="a3b3ff8jicf316993316069j03bdjfj" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" > <saml2:AuthnContext> <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef> </saml2:AuthnContext> </saml2:AuthnStatement> <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" > <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" >allen.li@gmail.com </saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement> </saml2:Assertion>
内容的提问来源于stack exchange,提问作者Allen Li
相关产品推荐
相关产品推荐

