SAML:为什么证书在签名中?


103

我必须为我公司的网站(作为信赖方)使用SAML实施SSO。当然,必不可少的部分是签名验证。这是我们的合作伙伴公司(声明方)的示例SAML的签名部分:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
 <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
  <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
  <ds:Reference URI="#_2152811999472b94a0e9644dbc932cc3" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
   <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
     <ec:InclusiveNamespaces PrefixList="ds saml samlp xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    </ds:Transform>
   </ds:Transforms>
   <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
   <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">bW1Os7+WykqRt5h0mdv9o3ZF0JI=</ds:DigestValue>
  </ds:Reference>
 </ds:SignedInfo>
 <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
cgrAN4T/UmobhrkkTi3miiRfbo0Z7aakSZjXuTWlZlu9jDptxPNbOFw8ZbYKZYyuW544wQqgqpnG
gr5GBWILSngURjf2N45/GDv7HMrv/NRMsRMrgVfFsKbcAovQdLAs24O0Q9CH5UdADai1QtDro3jx
nl4x7HaWIo9F8Gp/H1c=
 </ds:SignatureValue>
 <ds:KeyInfo>
  <ds:X509Data>
   <ds:X509Certificate>MIIElzCCA3+gAwIBAgIQNT2i6HKJtCXFUFRB8qYsZjANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQG
    EwJGUjEOMAwGA1UEBxMFUGFyaXMxDDAKBgNVBAoTA3BzYTEgMB4GA1UECxMXY2VydGlmaWNhdGUg
    YXV0aG9yaXRpZXMxKDAmBgNVBAMTH0FDIFBTQSBQZXVnZW90IENpdHJvZW4gUHJvZ3JhbXMwHhcN
    MDkwODE5MDcxNTE4WhcNMTEwODE5MDcxNTE5WjCBhjELMAkGA1UEBhMCZnIxHzAdBgkqhkiG9w0B
    CQEWEHBhc3NleHRAbXBzYS5jb20xGDAWBgoJkiaJk/IsZAEBEwhtZGVtb2IwMDEMMAoGA1UEChMD
    cHNhMREwDwYDVQQLEwhwcm9ncmFtczEbMBkGA1UEAxMSVGVzdCAtIFBBU1NFWFQgREVWMIGfMA0G
    CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuY1nrepgACvDSTLWk5A1cFOJSwDbl6CWfYp3cNYR0K3YV
    e07MDZn+Rv4jo3SusHVFds+mzKX2f8AeZjkA3Me/0yiS9UpS9LQZu9mnhFlZRhmUlDDoIZxovLXN
    aOv/YHmPeTQMQmJZu5TjqraUq7La1c187AoJuNfpxt227N1vOQIDAQABo4IBkTCCAY0wDgYDVR0P
    AQH/BAQDAgWgMB8GA1UdIwQYMBaAFLceWtTfVeRuVCTDQWkmwO4U01X/MAwGA1UdEwEB/wQCMAAw
    gbYGA1UdIASBrjCBqzCBqAYKKoF6ARfOEAEBBDCBmTBBBggrBgEFBQcCARY1aHR0cDovL3JldW5p
    cy5pbmV0cHNhLmNvbS9hdXRvcml0ZS9QQy1BQy1Qcm9ncmFtcy5wZGYwVAYIKwYBBQUHAgIwSDAK
    FgNwc2EwAwIBARo6UG9saXRpcXVlIGRlIENlcnRpZmljYXRpb24gQUMgUFNBIFBldWdlb3QgQ2l0
    cm9lbiBQcm9ncmFtczBcBgNVHR8EVTBTMFGgT6BNhktodHRwOi8vaW5mb2NlcnQucHNhLXBldWdl
    b3QtY2l0cm9lbi5jb20vQUMtUFNBLVBldWdlb3QtQ2l0cm9lbi1Qcm9ncmFtcy5jcmwwHQYDVR0l
    BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBYGA1UdDgQPBA1BVVRPX0dFTkVSQVRFMA0GCSqGSIb3
    DQEBBQUAA4IBAQCvRtP6bFkOUEHcqc6yUX0Q1Gk2WaAcx4ziUB0tw2GR9I0276JRJR0EGuJ/N6Fn
    3FhLQrSPmS97Xvc9XmiI66fQUdg64g9YqBecdiQlUkR20VLgI6Nq8pldQlWjU2iYlkP15U7VF4Qr
    0Pb2QiIljZUCKdv3qdED2Ri33za46LfykrlwZB0uhTVUxI/AEtjkKVFaZaqanJg+vJyZI5b30z7g
    Ff8L3ht4Z7SFKdmY3IQSGzElIAAUfduzTJX0cwnGSU9D4BJu1BS8hWnYPwhk+nBJ7OFhXdwYQFWq
    fhpBLq+ciJti9OMhcdCSIi0PbrOqzqtX7hZUQOvfShhCTJnl5TJJ</ds:X509Certificate>
  </ds:X509Data>
 </ds:KeyInfo>
</ds:Signature>

我只是不明白,为什么证书在签名中?

我的意思是通常我会以安全的方式从公司获得证书,所以我知道证书是从他们那里获得的。当签名验证成功时,我知道我们的合作伙伴公司已经签名。

但是,当证书在SAML响应的签名中时,任何人都可以发送它!我唯一知道的是,反应还没有被伪造。但是重点是,我不知道谁发送了SAML。

谁能向我解释,这是如何工作的?

Answers:


66

SAML响应带有签名和该签名的公共密钥。

您可以使用公共密钥来验证SAML响应的内容是否与该密钥匹配-换句话说,该响应肯定来自具有与消息中的公共密钥相匹配的私钥的人,并且响应尚未篡改。

我不知道您正在使用哪种技术,但是在.Net中,您可以像这样检查它:

// load a new XML document
var assertion = new XmlDocument { PreserveWhitespace = true };
assertion.LoadXml("The SAML XML that you were sent");

// use a namespace manager to avoid the worst of xpaths
var ns = new XmlNamespaceManager(assertion.NameTable);
ns.AddNamespace("samlp", @"urn:oasis:names:tc:SAML:2.0:protocol");
ns.AddNamespace("asrt", @"urn:oasis:names:tc:SAML:2.0:assertion");
ns.AddNamespace("dsig", @"http://www.w3.org/2000/09/xmldsig#");

// get nodes down to the signature
var responseNode = assertion.SelectSingleNode("/samlp:Response", ns);
var assertionNode = responseNode.SelectSingleNode("asrt:Assertion", ns);
var signNode = assertionNode.SelectSingleNode("dsig:Signature", ns);

// load the XML signature
var signedXml = new SignedXml(assertion.DocumentElement);
signedXml.LoadXml(signNode as XmlElement);

// get the certificate, basically:
//     signedXml.KeyInfo[0].Certificates[0]
// ...but with added casting
var certificate = GetFirstX509Certificate(signedXml);

// check the key and signature match
bool isSigned = signedXml.CheckSignature(certificate, true);

那只是检查消息是来自它说的是谁。您需要额外检查邮件是否来自您信任的人,并且检查速度较慢-它需要包括撤销,并且可能需要验证整个证书链。

通常,这是您将接受SAML响应的公共密钥的列表。

然后,您可以检查此消息是否未被篡改,并且来自您信任的人,因此您可以授权在提供的SAML属性中提供的用户详细信息。

可能已经有了公共密钥,这意味着签名不需要再次包含公共密钥,但是您也可以有多个可能的已知发件人,甚至是一系列已知发件人。

例如,您可能有两个受信任的提供程序-在任何一种情况下,您都要检查消息是否未被篡改,然后再检查您是否信任任何一个提供程序。如果密钥不在签名中,则断言可以小一些,但是现在您必须提前知道断言来自哪个身份提供者。

因此,实际上,公钥位于签名中有两个主要原因:

  1. 篡改检查比身份检查更快,如果知道公钥,可以将其隔离。
  2. 如果密钥在断言中,则支持多个身份容易得多。

2
@svlada SAML断言不需要其自身的加密,因为文本本身可以通过SSL发送-整个用户会话应为HTTPS。假定已知的可信发件人已对断言进行签名并且未对其进行篡改的验证就足够了。
基思

5
@svlada不得在没有SSL的情况下进行基于HTTP的身份验证(任何形式)。对证书进行加密将阻止中间人(MitM)读取它,但不会阻止他们以类似于基于cookie的MitM攻击的方式重新使用它。
基思(Keith)

8
SAML回应也没有要求包括该签名的公钥。SAML2规范的第5.4.5节指出:“ XML签名定义了<ds:KeyInfo>元素的用法。SAML不需要使用<ds:KeyInfo>,也没有对其使用施加任何限制。因此,<ds :KeyInfo>可能不存在。” 如果通过其他方式(例如在实施SAML使用者之前存储在本地证书存储区中)提供了公钥,则可以验证签名。
Sam Rueby 2014年

2
@ Sam.Rueby啊,我会纠正它。我见过的每个实现都包含了密钥。
基思2014年

5
@Jez整个协议就像地狱一样令人困惑。断言基本上是自包含的-您可以检查自私钥对其进行签名以来是否未对其进行篡改。您无需自己拥有公用密钥即可执行此操作(因此,我知道此断言来自Dave,并且自Dave签署以来没有人对其进行篡改,但我可能不知道Dave是谁,或者我是否可以信任他)。然后,在确认之后,我可以检查公用密钥是否是我信任的密钥。我认为这是因为最终检查可能会延迟(我去询问办公室是否有人认识戴夫时)
Keith 2015年

41

指定密钥的原因是,身份提供者的元数据可以指定多个签名密钥,并且可以通过将其包括在签名中来指定要使用的密钥。SAML 2.0要求,如果未使用来指定密钥Assertion,则可以通过上下文(从声明方的元数据)来推断密钥。

例如,您可能在断言方的元数据中包含以下内容:

        <KeyDescriptor>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>
BQUAMCMxITAfBgNVBAMTGGlkcDEudGFuZ29oZWFsdGhkZW1vLmNvbTAeFw0xMzA1
...snip...
ttHq2Wi5J7img1M2zo28hH5DK78S+XerfXHK2HEZYZs=
                </ds:X509Certificate>
            </ds:X509Data>
            <ds:X509Data>
                <ds:X509Certificate>
H24a88h7zlq+pnAxQm0CAwEAAaN3MHUwVAYDVR0RBE0wS4IYaWRwMS50YW5nb2hl
...snip...
mg1M2zo28hH5DK78=
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </KeyDescriptor>

每个已签名的XML元素都可以指定哪个密钥用于签名。但是,对于SAML 2.0,该签名密钥必须(例如)与元数据中为生成签名的一方定义的密钥匹配。如果与签名一起提供的密钥不受信任(在这种情况下,未在元数据中指定),则SAML系统在验证签名时必须生成错误。


9
我认为这很重要,因为响应中的证书必须与元数据中的证书匹配。否则,我可以使用我想要的任何证书对响应进行签名,然后发送其公钥进行验证。
dana 2013年

5
我认为这是最好的答案,在我看来,其他答案都没有抓住重点,即根据消息本身中声明的密钥检查消息并不能为您提供任何安全性...您仍然必须检查消息中的密钥是正确的!(在这种情况下,您必须确保它位于受信任的元数据中)。
rchampourlier

3
完全同意上面的评论-消息中传递的证书本身是一文不值的,因为签名的全部要点是验证消息是否可信。如果消息不可信,则捆绑的证书也不是。
2015年

@jbindel-谢谢!如果可能,我会有一个newby问题:该SAML证书是否必须与当前的物理证书匹配,还是仅用于实现元数据匹配?我之所以这么问,是因为我担心IdP对其证书重新设置密钥对操作产生的影响-在这一点上,它大概与元数据密钥不同步。如果2被并列,那么我很担心。运营影响,即 除非SP和IdP都手动更新了SAML2密钥,否则所有SSO都将失败,并且如果技术交流不完善,则会对SSO用户产生影响。(如果是愚蠢的问题,则表示歉意)
Pancho

SP元数据必须包含证书,但是SP元数据可以指定旧的和新的IdP证书。如果IdP正在更新其证书,则可以将其添加到SP元数据中。一旦应该使用旧证书完成IdP,则可以将其从SP元数据中删除。那符合您的要求吗?我知道这在Shibboleth SP上效果很好。SP元数据文件仅需要具有<KeyDescriptor use="signing">将由SP接受的IdP证书的元素。
jbindel '16

8

签名证书的公共部分在SAML消息中。这用于检查令牌本身的签名,当然还可以使接收者知道是谁发行了令牌并对其进行相应的处理。

它包含在XML数字签名规范的一部分中,实际上并不是SAML的任何特定内容。没有证书,您如何分辨令牌的来源以及如何验证令牌?

XmlDSig确实指定了其他方法,您可以通过主题,序列号,哈希等来识别签名密钥,但是这假定接收方具有公共证书。对于SAML,情况可能并非如此,因此嵌入了X509证书的公共部分。


1
“没有证书,您如何知道令牌的来源,以及如何验证令牌?” - 你在说什么?为了信任SAML消息中的签名,您必须已经具有受信任的公共证书的列表。您可以使用该Issuer元素并针对该元素存储该发行者的证书,然后选择要用来检查此消息签名的证书。
Jez 2015年

2
绝对不是真的。您可以信任证书颁发者(如CA),而不必信任它颁发的单个证书,也不必保留每个证书的本地副本。
2015年

3
吹牛意味着您信任由CA颁发的任何其他有效证书签名的saml令牌。买一个不是不可能的!为确保您的令牌来自@Jez提到的正确来源,您应该已经有一个受信任的公共证书列表。
太阳

2
@Sun,不正确。这就像说,如果富国银行拥有相同的CA,就可以冒充美国银行。X509证书具有可以验证的正确身份的主题DN。
保罗·德雷珀

+1尤其是用于识别这是XML数字签名规范的一部分,这对于新手来说并不明显,对于理解消息的实际处理方式至关重要,因为几乎每个SAML实现都依赖XML库来完成。繁重的工作。
BryKKan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.