Luna Tech

Tutorials For Dummies.

SSO Keys

2021-08-15


0. 前言

这篇来讲讲 SSO security 相关的知识。


1. 两对 key

  1. SP 有一对 public key 和 private key
  2. IdP 有一对 public key 和 private key

SAML AuthnRequest

这个 request 是 SP 发送给 IdP 的,那么 SP 需要 sign 这个 request。

Sign 的时候用哪个 key 呢?

答案是:用 SP 的 private key,IdP 会用 SP 的 public key 去验证签名。

SAML Response

这个 response 是 IdP 回复给 SP 的,IdP 需要用自己的 private key 去签名,然后 SP 用 IdP 的 public key 去验证签名。

小结

双方互换公钥,发消息的那方用私钥加密,收消息的那方用公钥解密。

最常用的 signing algorithm 是 RSA with SHA-256。


2. SAML Request & Response

SAML AuthnRequest 和 SAML Response 都包含 SAML Assertion。

Request

SAML Authentication Example - SAML AuthnRequest Examples | SAMLTool.com

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="ONELOGIN_809707f0030a5d00620c9d9df97f627afe9dcc24" Version="2.0" ProviderName="SP test" IssueInstant="2014-07-16T23:52:45Z" Destination="http://idp.example.com/SSOService.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs">
  <saml:Issuer>http://sp.example.com/demo1/metadata.php</saml:Issuer>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
  <samlp:RequestedAuthnContext Comparison="exact">
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

Response

SAML Response Examples - SAML Assertion Example | SAMLTool.com

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
    <saml:Subject>
      <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
        <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

签哪里?

默认是双方都在 SAML Assertion 上签名,也可以选择签整个 Request 和整个 Response。

Best Practice: Assertion 单独签名 + 整个 Request/Response 签名。

为什么?Assertion 需要被重复使用,所以最好是单独签一个,而签整个 request/response 也可以防止黑客获取数据,修改一些 xml attributes。

We can protect the message, we can trust both the entire protocol message while also being able to reuse assertions.


3. 签名和加密的区别

Signing is producing a “hash” with your private key that can be verified with your public key. The text is sent in the clear. Encrypting uses the receiver’s public key to encrypt the data; decoding is done with their private key. So, the use of keys is not reversed (otherwise your private key wouldn’t be private anymore!).

签名:自己私钥加密,对方用公钥解密;

加密:用对方公钥加密,对方用私钥解密;

加密版 SAML Assertion

不光要用自己的 private key 去签名,还要用对方的 public key 去加密 assertion。

不过 SAML assertion 本来就是通过 HTTPS 传输的,所以也不是明文。

注:Azure Enterprise Application 提供这个额外的功能。