当前位置:首页 > IT科技

安全断言标记语言SAML2.0的认证机制与重要性

【.com快译】作为一种在各个服务之间交换认证和授权信息的安全方法,安全断言标记语言(Security Assertion Markup Language,标记SAML)2.0经常被企业用在构建内部单点登录(single sign-on,证机制重SSO)方案的安全过程中,以实现用户登录到统一的标记身份认证服务处,进而授予他们对于其他内部服务子集的证机制重访问权限。

从安全角度来看,安全采用SAML/SSO的标记优势主要体现在如下方面:

提供单一的身份来源。当有员工加入或离开公司时,证机制重您既不必事无巨细地去更新每一项内部服务,安全又不必担心错过某个关联性的标记重要服务。 强制执行一致性的证机制重认证。可实施SAML/SSO的安全方法包括:多因素认证和会话持续时间等。

下面,标记我们将重点讨论SSO和SAML2.0的证机制重认证机制与重要性。

SAML的相关术语

主体(Principal)

主体是参与认证的用户。您可以将其视为屏幕后面的实际访问者。在下文中,我们将其假设为John Smith。主体通常会带有诸如:名字、网站模板姓氏、电子邮件地址等附加的元数据(metadata)。此类元数据往往也被称为身份信息(identity information),下面我们将重点阐述其重要性。

身份提供者(Identity Provider)

身份提供者常被简称IdP,是提供身份信息和认证判断的源服务。我们可以将身份提供者视为包含身份信息的数据库。它能够认证主体,并将身份信息返回给服务提供者(详见下文)。其中,最常见身份提供者应用包括:Auth0、活动目录联合服务(Active Directory Federation Services,ADFS)和Okta。在实践中,人们往往会将组织的所有用户身份都整合到一个身份提供者处。

服务供应者(Service Providers)

服务提供者通常被缩写为SP,是向主体要求进行认证和获取身份信息的服务。服务提供者获取由身份提供者提供的认证响应,并使用该信息来创建和配置各种会话。也就是说,服务提供者是某个应用程序,它通过为其用户提供单点登录(SSO)机制,来实现资源的源码库登录和访问。

此类应用程序除了知晓主体的名称或邮件地址以外,还需要请求获得主体的其他身份信息,以实现基于角色的访问控制(role-based access control,RBAC)。典型的服务提供者应用包括:Github、Google Apps、以及Teleport(针对SSH和Kubernetes的一种访问解决方案)。

流程(Flows)

目前,SAML支持两种不同类型的流程:由服务提供者初始化的流程、以及由身份提供者初始化的流程。服务提供者初始化的流程往往是从服务提供者开始,被重定向到身份提供者处进行认证,然后在被重定向回服务提供者。该流程通常在用户单击“使用SSO登录”按钮时被启动。

绑定(Bindings)

绑定是指在服务提供者和身份提供者之间传输的数据格式。HTTP重定向绑定和HTTP POST绑定是目前最为流行的两种模式。其中,HTTP重定向绑定使用HTTP重定向和查询参数来传输数据;此类绑定通常被用在认证的云服务器请求中。HTTP POST绑定则使用各种HTTP POST表单来传输数据,此类绑定通常被用在认证的响应中。

断言(Assertions)

断言是身份提供者对主体所做的声明,包括:主体的电子邮件地址、与之关联的组或角色等。服务提供者使用断言为主体创建和配置会话。也就是说,断言定义了身份提供者在向服务提供者传送的过程中,包含了主体具有哪些身份信息。

SAML的登录流

为了说明SAML登录的工作原理,我们将在如下示例中使用Teleport作为服务提供者,使用Auth0作为身份提供者。SAML登录的基本流程,如下图所示:

1. 用户单击“通过Auth0登录”按钮,选择使用SAML登录,而不是使用Teleport的内置用户数据库。Teleport会将用户重定向到Auth0处。在此,用户便是SAML中的主体。

2. Auth0要求用户提供他们的用户名(或电子邮件)、密码、以及认证令牌作为第二认证因素(2FA)。

3. 如果提供的信息正确,Auth0将获取主体的身份信息,并将其作为断言返回给Teleport。

4. Teleport会从Auth0处接收到身份信息,进而创建用户会话。

配置

身份提供者往往拥有自己独特的配置方法。下面是身份提供者与服务提供者在协作时需要的最少配置集:

断言消费者服务(Assertion Consumer Service,ACS)的URL是服务提供者的端点,身份提供者将其认证的响应重定向到该端点处。由于它将被用于传输个人身份信息(Personally Identifiable Information,PII),因此该端点应当被配置为HTTPS类型。 生成并上传用于签发认证请求的签名密钥(详见下文)。 对断言中所包含的有关主体信息的来源和格式进行配置。身份提供者至少需要发送NameID、以及组成员等信息。

服务提供者的配置通常比较简单,并且可以通过解析身份提供者所提供的元数据,来自动完成配置。如下Django(译者注:一个开放源代码的Web应用框架,由Python编写而成。)代码段展示了简单的身份提供者元数据的XML。其中,最重要的标签当属SingleSignOnService和KeyDescriptor。具体而言,SingleSignOnService标签定义了有待发送认证请求的绑定和端点,而KeyDescriptor标签则包含了有待认证响应的身份提供者的公钥。

<md:EntityDescriptor>   <md:IDPSSODescriptor>     <md:KeyDescriptor use="signing">       <ds:KeyInfo>         <ds:X509Data>           <ds:X509Certificate>             MIICMjCCAZugAwIBAgIBADANBgkqhkiG9w0BAQ0FADA2MQswCQYDVQQGEwJ1czEL             MAkGA1UECAwCQ0ExDDAKBgNVBAoMA2lkcDEMMAoGA1UEAwwDaWRwMB4XDTE5MDQy             NjE4NTIxOFoXDTIwMDQyNTE4NTIxOFowNjELMAkGA1UEBhMCdXMxCzAJBgNVBAgM             AkNBMQwwCgYDVQQKDANpZHAxDDAKBgNVBAMMA2lkcDCBnzANBgkqhkiG9w0BAQEF             AAOBjQAwgYkCgYEA1mKmlbr/SiHOhgdROpYeze96mw0WbO+BdJYDceeuNkaw0zOU             CKZI6TNgrNsqEnLOyWYy5ywA9XA6Ni2qQTuKqapsMT3I1s9DMUg2ln7tTzNdhE02             fY4GVjiCw7i9YJ+cgcMZh8qL0yoilrLpRLzLrRC6rApqYfEwn+5FPKtTt7cCAwEA             AaNQME4wHQYDVR0OBBYEFNvFMRtHJ4D327dbRbxhWceXnwd0MB8GA1UdIwQYMBaA             FNvFMRtHJ4D327dbRbxhWceXnwd0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN             BQADgYEAX0I5zpGqI7vzzs8CDyokux1JZzfu+O3P5GfOwUaIG9y01FzxgbL2MRKQ             oTXMAed97Q6vHA5cffvteu/rPcerpGmFj5h3wv5u+D0ch5s/Mk/Ug6S+x6k3CC+P             kHimi6OEslFecDMhghUtPJAmhOGnTRwLr7hVeJXBHXWCTXA7aGE=           </ds:X509Certificate>         </ds:X509Data>       </ds:KeyInfo>     </md:KeyDescriptor>     <md:NameIDFormat>        urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress     </md:NameIDFormat>     <md:SingleSignOnService       Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"       Location="https://idp.example.com/saml"/>     <md:SingleSignOnService        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"       Location="https://idp.example.com/saml"/>   </md:IDPSSODescriptor> </md:EntityDescriptor> 

认证请求

在主体登录的过程中,服务提供者会创建一个AuthnRequest的XML文档,通过对其序列化(可采用base64、压缩和URL编码),将其作为查询参数添加到URL中,并将主体的浏览器重定向到身份提供者的登录页面处。服务提供者会请求身份提供者以HTTPS的方式,代为执行认证。如下URL示例便是由HTTP重定向使用绑定AuthnRequest发送的:

https://idp.example.com/saml?SAMLRequest=nFdpk6JK0%2F0rHc7... 

如下Django代码段展示了由AuthnRequest编码的SAMLRequest简化参数:

<md:IDPSSODescriptor>    <md:KeyDescriptor use=&quot;signing&quot;>      <ds:KeyInfo>        <ds:X509Data>          <ds:X509Certificate>            MIICMjCCAZugAwIBAgIBADANBgkqhkiG9w0BAQ0FADA2MQswCQYDVQQGEwJ1czEL            MAkGA1UECAwCQ0ExDDAKBgNVBAoMA2lkcDEMMAoGA1UEAwwDaWRwMB4XDTE5MDQy            NjE4NTIxOFoXDTIwMDQyNTE4NTIxOFowNjELMAkGA1UEBhMCdXMxCzAJBgNVBAgM            AkNBMQwwCgYDVQQKDANpZHAxDDAKBgNVBAMMA2lkcDCBnzANBgkqhkiG9w0BAQEF            AAOBjQAwgYkCgYEA1mKmlbr/SiHOhgdROpYeze96mw0WbO+BdJYDceeuNkaw0zOU            CKZI6TNgrNsqEnLOyWYy5ywA9XA6Ni2qQTuKqapsMT3I1s9DMUg2ln7tTzNdhE02            fY4GVjiCw7i9YJ+cgcMZh8qL0yoilrLpRLzLrRC6rApqYfEwn+5FPKtTt7cCAwEA            AaNQME4wHQYDVR0OBBYEFNvFMRtHJ4D327dbRbxhWceXnwd0MB8GA1UdIwQYMBaA            FNvFMRtHJ4D327dbRbxhWceXnwd0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN            BQADgYEAX0I5zpGqI7vzzs8CDyokux1JZzfu+O3P5GfOwUaIG9y01FzxgbL2MRKQ            oTXMAed97Q6vHA5cffvteu/rPcerpGmFj5h3wv5u+D0ch5s/Mk/Ug6S+x6k3CC+P            kHimi6OEslFecDMhghUtPJAmhOGnTRwLr7hVeJXBHXWCTXA7aGE=          </ds:X509Certificate>        </ds:X509Data>      </ds:KeyInfo>    </md:KeyDescriptor>    <md:NameIDFormat>       urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress    </md:NameIDFormat>    <md:SingleSignOnService      Binding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&quot;      Location=&quot;https://idp.example.com/saml&quot;></md:SingleSignOnService>    <md:SingleSignOnService       Binding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect&quot;      Location=&quot;https://idp.example.com/saml&quot;></md:SingleSignOnService>  </md:IDPSSODescriptor> /md:EntityDescriptor>" 

服务提供者会生成一个较大的安全随机数,并将其插入AuthnRequest标签中的ID字段。该值通常会被存储在本地数据库中,可用于将请求与来自身份提供者的响应进行比对,以防止恶意的第三方在不知道ID的情况下,发送未经请求的响应。

同时,为了防止重复使用已过期的AuthnRequests,身份提供者需要存储和跟踪那些已被使用过的ID值。可见,如果没有时间限制的话,这将会导致身份提供者所需的存储量不断攀升。而IssueInstant恰好可以为请求产生有效的窗口。

服务提供者负责签发AuthnRequest。而在SAML的签名方案中包含了:签名、用于签发请求的密钥、以及有关如何在Signature标签中计算签名的所有信息。因此身份提供者不仅应该认证用于签发请求的密钥,还应该认证该密钥是否与在配置时上传的密钥为同一个(请参阅上一节)。如果密钥或签名值不匹配、或丢失的话,身份提供者就会判定请求为非法,并直接拒绝之。实际上,SAML会使用XML数字签名来签发请求的内容,其本身是一个庞大而复杂的主题。您可以通过链接--https://www.di-mgt.com.au/xmldsig.html,来进一步了解如何使用XMLDSIG去签发XML文档。

认证响应

接着,让我们回到认证的流程。如果主体输入了正确的登录凭据,身份提供者将会对服务提供者的ACS URL(例如,在本示例中为--https://sp.example.com/saml/acs)执行“302重定向”。其正文中包含了认证的响应。如下的Django代码段是一个简化版的SAMLResponse:

saml2p: Response Destination=\"https://sp.example.com/saml/acs\" ID=\"id35287812421219341967493380\" InResponseTo=\"bcf0b634-67b4-4dc9-a436-4e5cfcfb80e2\" IssueInstant=\"2019-04-18T18:51:46.729Z\"> <ds:Signature> <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=\"#id35287812421219341967493380\"> <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#\",/> </ds:Transforms> <ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\" /> <ds:DigestValue> tyLUm4r2isgN+L6sRcqDSEa1Zb7WQbQJG6PpLcf3Mrc= </ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> XjqbZty/QkqTnMV8YsS2XJ3qgVLPGNC67o/WmzkzoAyl3SBOCGllV4UdijkTjhgykQP7MVXyCql0 eRtIMJ++rbi3OxCSc0LN67znuTS7cAfcOQzYBtYX2R9w3GlEAO0kZusWYlP3cu/ObmQZUQ7CSgr4 DRXsVWRhSmmpxHl6klC6c10eWiIlK7Ccpvvvb2hlwl8anyuO/CcKH0n/Rb9vHWtsAlqKXZ8G4X6M 77AfRFC7yDWk+8B784109phQxcxoDYjuQNO5IkiRE6J2LnkmuaPoKVyTtpP2JYLiYMSBu8laDsnZ I/ewOtBwr16j9oOJpgHPQufQJfvcg+rPEwkptg== </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> MIICMjCCAZugAwIBAgIBADANBgkqhkiG9w0BAQ0FADA2MQswCQYDVQQGEwJ1czEL MAkGA1UECAwCQ0ExDDAKBgNVBAoMA2lkcDEMMAoGA1UEAwwDaWRwMB4XDTE5MDQy NjE4NTIxOFoXDTIwMDQyNTE4NTIxOFowNjELMAkGA1UEBhMCdXMxCzAJBgNVBAgM AkNBMQwwCgYDVQQKDANpZHAxDDAKBgNVBAMMA2lkcDCBnzANBgkqhkiG9w0BAQEF AAOBjQAwgYkCgYEA1mKmlbr/SiHOhgdROpYeze96mw0WbO+BdJYDceeuNkaw0zOU CKZI6TNgrNsqEnLOyWYy5ywA9XA6Ni2qQTuKqapsMT3I1s9DMUg2ln7tTzNdhE02 fY4GVjiCw7i9YJ+cgcMZh8qL0yoilrLpRLzLrRC6rApqYfEwn+5FPKtTt7cCAwEA AaNQME4wHQYDVR0OBBYEFNvFMRtHJ4D327dbRbxhWceXnwd0MB8GA1UdIwQYMBaA FNvFMRtHJ4D327dbRbxhWceXnwd0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN BQADgYEAX0I5zpGqI7vzzs8CDyokux1JZzfu+O3P5GfOwUaIG9y01FzxgbL2MRKQ oTXMAed97Q6vHA5cffvteu/rPcerpGmFj5h3wv5u+D0ch5s/Mk/Ug6S+x6k3CC+P kHimi6OEslFecDMhghUtPJAmhOGnTRwLr7hVeJXBHXWCTXA7aGE= </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2p:Status> <saml2p:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\" /> </saml2p:Status> <saml2:Assertion ID=\"id35287812421980111258419174\" IssueInstant=\"2019-04-18T18:51:46.729Z\"> <ds:Signature> <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=\"#id35287812421980111258419174\"> <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#\"/> </ds:Transforms> <ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\" /> <ds:DigestValue> VKPsgTPABNq1SvInCMXd04LZCvRYMnJzEeT5oIs70hw= </ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> gsUzQuivXX378HkYNI+plBkp1BvPUNmJD+kh825nHwIBNd019IxffVmOfRAQAkZhT6rqxWhO5/Yc JGR5J0qjJVmrRrJ/ipT4VfuJsbn346nEFSMU15D0h3UHrvl651C+NStyXsi8Q8502Qe0ChHOtEXM rw9HWPwYtJX0rlpNEzLUnEQPvJ4pd3bz9SIl/YXMNTxE7NCDOxPXKtA4namkkweilxTCynM6A1kn 6gEWaXhLMwLLAV6kOtivdVksBPzR9BeZ7RPpXeqt0qN62L4NaHq3OsdjgtQr9sllssD1fEek1eU4 giCzPgb1+LjvD9dpFH5pcLt9YlwHyYgEBBLOQg== </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> MIICMjCCAZugAwIBAgIBADANBgkqhkiG9w0BAQ0FADA2MQswCQYDVQQGEwJ1czEL MAkGA1UECAwCQ0ExDDAKBgNVBAoMA2lkcDEMMAoGA1UEAwwDaWRwMB4XDTE5MDQy NjE4NTIxOFoXDTIwMDQyNTE4NTIxOFowNjELMAkGA1UEBhMCdXMxCzAJBgNVBAgM AkNBMQwwCgYDVQQKDANpZHAxDDAKBgNVBAMMA2lkcDCBnzANBgkqhkiG9w0BAQEF AAOBjQAwgYkCgYEA1mKmlbr/SiHOhgdROpYeze96mw0WbO+BdJYDceeuNkaw0zOU CKZI6TNgrNsqEnLOyWYy5ywA9XA6Ni2qQTuKqapsMT3I1s9DMUg2ln7tTzNdhE02 fY4GVjiCw7i9YJ+cgcMZh8qL0yoilrLpRLzLrRC6rApqYfEwn+5FPKtTt7cCAwEA AaNQME4wHQYDVR0OBBYEFNvFMRtHJ4D327dbRbxhWceXnwd0MB8GA1UdIwQYMBaA FNvFMRtHJ4D327dbRbxhWceXnwd0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN BQADgYEAX0I5zpGqI7vzzs8CDyokux1JZzfu+O3P5GfOwUaIG9y01FzxgbL2MRKQ oTXMAed97Q6vHA5cffvteu/rPcerpGmFj5h3wv5u+D0ch5s/Mk/Ug6S+x6k3CC+P kHimi6OEslFecDMhghUtPJAmhOGnTRwLr7hVeJXBHXWCTXA7aGE= </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2:Subject> <saml2:NameID> jsmith@example.com </saml2:NameID> <saml2:SubjectConfirmation> <saml2:SubjectConfirmationData InResponseTo=\"bcf0b634-67b4-4dc9-a436-4e5cfcfb80e2\" NotOnOrAfter=\"2019-04-18T18:56:46.730Z\" Recipient=\"https://sp.example.com/saml/acs\" /> </saml2:SubjectConfirmation> </saml2:Subject> <saml2:Conditions NotBefore=\"2019-04-18T18:46:46.730Z\" NotOnOrAfter=\"2019-04-18T18:56:46.730Z\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\"> </saml2:Conditions> <saml2:AuthnStatement AuthnInstant=\"2019-04-18T18:51:46.729Z\" SessionIndex=\"bcf0b634-67b4-4dc9-a436-4e5cfcfb80e2\"> </saml2:AuthnStatement> <saml2:AttributeStatement> <saml2:Attribute Name=\"logins\"> <saml2:AttributeValue> root </saml2:AttributeValue> <saml2:AttributeValue> jsmith </saml2:AttributeValue> </saml2:Attribute> <saml2:Attribute Name=\"groups\"> <saml2:AttributeValue> admins </saml2:AttributeValue> <saml2:AttributeValue> developers </saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement> </saml2:Assertion> </saml2p:Response> 

当服务提供者接收到认证响应时,应当检查InResponseTo属性所引用的AuthnRequest的ID,是否由真实的服务提供者所发送。同时,IssueInstant属性可以用来确定响应的有效性窗口的范围。

由于认证响应被传递到ACS URL处时并不会执行客户端认证,因此这就是为什么我们需要Signature去认证响应中的客户端,是否为真实的身份提供者的原因。这与webhooks(一种自动化部署)的概念非常相似:那些被用于认证客户端的信息(在webhooks中通常是指API密钥)需要提前在带外完成交换。

对应的响应中有着四个新的标签:Status、Subject、Conditions、以及AttributeStatement。其中:

Status包含了认证是否成功的结果。 Subject标识了通过认证的主体。例如在上例中,NameID标签就包含了认证主体的电子邮件地址:jsmith@example.com。 Conditions定义了断言的限制。例如,NotBefore和NotOnOrAfter属性定义了断言有效期的持续时长。这样可以防止恶意行为者通过记录有效的认证响应,进行重放(replaying)攻击。 AttributeStatement包含了身份提供者针对主体所做出的断言。如前所述,断言通常会包含诸如:组织内部的组成员身份、受允许的登录、以及有关主体的其他识别信息。在上例中,该主体属于admins和developers组,并被允许以root和jsmith身份登录。

可见,我们需要记住的是:主体的断言只是在识别信息时的一个快照,如果提供长期存在(long-lived)的断言、或会话,就会存在安全隐患。因此,我们需要让断言和会话保持合理且短暂(short-lived),以及通过强制性的重新认证,来确保身份提供者对主体所做出的断言的有效性。

小结

综上所述,服务提供者会根据判断的结果,来提供响应。只有成功的响应才会在内部服务中创建会话,提供单一的身份源,以及实现横跨内部服务的一致性认证。为此,服务提供者通常需要知道主体所属的用户组,并据此实施基于角色的访问控制策略。例如,只有来自“SSH”组的用户,才能够访问生产环境;而其他组的用户,则需要根据不同的策略,去访问Kubernetes集群、或CI/CD管道。

总的说来,SAML认证解决了如下三个重要问题:

SAML显著改善了用户的体验。用户只需要记住他们常用的单一身份凭据,而不必针对不同的应用,使用不同的用户名和密码。 SAML允许应用程序开发人员将身份管理和认证实施,外包给外部的提供者,而无需自行实现。 最重要的是,SAML显著降低了组织内针对访问管理的运营开销。如果有员工离开或转移到其他团队,他们的访问权限将会在连接到身份提供者所对应的应用时,自动被撤销或降级。

原文标题:How SAML 2.0 Authentication Works and Why It Matters,作者:Ev Kontsevoy

【译稿,合作站点转载请注明原文译者和出处为.com】

分享到:

滇ICP备2023006006号-16