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

Dan*_*nte 97 certificate signature saml

我必须为我公司的网站(作为依赖方)使用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>
Run Code Online (Sandbox Code Playgroud)

我不明白的是,为什么签名内的证书?

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

但是当证书在SAML-Response的签名范围内时,任何人都可以发送它!我唯一知道的是答案没有被证伪.但重点是,我不知道谁发送了SAML.

任何人都可以向我解释,这是如何工作的?

Kei*_*ith 61

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);
Run Code Online (Sandbox Code Playgroud)

这只是检查消息来自它所说的人.您需要额外检查消息是否来自您信任的人,并且此检查较慢 - 它需要包括撤销,并且可能需要验证整个证书链.

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

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

可能已经拥有公钥,这意味着签名不需要再次包含公钥,但您可能还有多个可能的已知发件人,甚至是已知发件人链.

例如,您可能有两个可信赖的提供者 - 在任何一种情况下,在检查您是否信任任一提供者之前,检查消息是否未被篡改.如果密钥不在签名中,则断言可以稍微小一些,但现在您必须事先知道断言来自哪个身份提供者.

所以,实际上,公钥在签名中有两个主要原因:

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

  • SAML响应不要求**包含该签名的公钥.SAML2规范的第5.4.5节规定"XML签名定义了<ds:KeyInfo>元素的用法.SAML不需要使用<ds:KeyInfo>,也不对其使用施加任何限制.因此,<ds :KeyInfo>可能缺席." 如果已通过其他方式向您提供公钥,则可以验证签名,例如,在实施SAML使用者之前存储在本地证书存储中. (7认同)
  • @Jez整个协议就像地狱一样令人困惑.基本上断言是自包含的 - 您可以检查它是否已被篡改,因为私钥已签名.你可以在没有公钥的情况下做到这一点(所以我知道这个断言来自Dave,并且自从Dave签名以来没有人篡改它,但我可能不知道Dave是谁或者我是否可以信任他).然后,在验证之后,我可以检查公钥是否是我信任的公钥.我想这是因为最后的检查可能有延迟(当我去询问办公室是否有人知道戴夫时) (4认同)
  • @svlada没有基于HTTP的身份验证(任何类型)都应该在没有SSL的情况下完成.加密证书将阻止中间人(MitM)阅读它,但它不会阻止他们以类似于基于cookie的MitM攻击的方式重新使用它. (3认同)
  • @svlada SAML断言不需要它自己的加密,因为文本本身可以通过SSL发送 - 整个用户会话应该是HTTPS.鉴于已知的,可信的发件人签署了断言并且未被篡改的验证就足够了. (2认同)
  • @ Sam.Rueby啊,我会纠正的.我见过的每个实现都包括密钥. (2认同)
  • @gubble是,并且(假设他们正确地做了)该消息将通过_tamper check_但是_identity check_失败,除非他们是你信任的人.对于该模式存在现实世界的情况,例如,可能存在允许更改响应的某种代理(例如,允许NSA窥探私有消息)但客户端仍将接受新签名.所以:这条消息是由Bob签署的,我们相信Bob,来自Bob的其他消息被NSA拦截,编辑和签名,我们也信任他们. (2认同)

jbi*_*del 35

指定密钥的原因是身份提供程序的元数据可以指定多个签名密钥,您可以通过将密钥包含在签名中来指定要使用的密钥.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>
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为这是一个重要的观点,即响应中的证书必须与元数据中的证书相匹配.否则,我可以用我想要的任何证书签署响应,并发送其公钥进行验证. (8认同)
  • 我认为这是最好的答案,在我看来,其他人都忽略了这样的观点,即根据消息中声明的密钥检查消息并没有给你任何安全性......你仍然必须检查消息中的密钥是正确的!(在这种情况下,您必须确保它在受信任的元数据中). (5认同)
  • 完全同意上述评论 - 消息中传递的证书本身*毫无价值*因为签名的全部内容是验证消息是否值得信赖.如果消息不值得信任,那么捆绑的证书也不是. (3认同)

blo*_*art 9

签名证书的公共部分位于SAML消息中.这用于检查令牌本身的签名,当然也允许接收者告知谁发出令牌并相应地对其进行处理.

事实上,它存在于XML数字签名规范的一部分,它实际上并不是SAML特有的.如果没有证书,你怎么知道令牌来自哪里,你怎么能验证它?

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

  • blowdart表示您信任由CA颁发的任何其他有效证书签名的saml令牌.买一个也不是不可能的!为确保您的令牌来自@Jez提到的正确来源,您应该已经拥有可信公共证书列表. (3认同)
  • “没有证书,你怎么知道令牌来自哪里,你怎么验证它?” - 你在说什么?为了信任 SAML 消息中的签名,您必须*已经* 拥有受信任的公共证书列表。您可以使用 `Issuer` 元素并根据该元素存储该颁发者的证书,然后选择该证书来检查此消息的签名。 (2认同)
  • 根本不是真的 Jez。您可以信任证书颁发者(如 CA),而不必信任它颁发的各个证书,也不必保留每个证书的本地副本。 (2认同)
  • @Sun,不正确。这就像说 Wells Fargo 可以冒充美国银行,如果他们拥有相同的 CA。X509 证书具有可以验证正确身份的主题 DN。 (2认同)