首頁 > 科技

安全斷言標記語言SAML2.0的認證機制與重要性

2021-06-24 12:35:43

作為一種在各個服務之間交換認證和授權資訊的方法,安全斷言標記語言(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執行「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顯著降低了組織內針對訪問管理的運營開銷。如果有員工離開或轉移到其他團隊,他們的訪問許可權將會在連線到身份提供者所對應的應用時,自動被撤銷或降級。


IT145.com E-mail:sddin#qq.com