SAML和OAuth2這兩種SSO協議的區別

flydean發表於2021-01-02

簡介

SSO是單點登入的簡稱,常用的SSO的協議有兩種,分別是SAML和OAuth2。本文將會介紹兩種協議的不同之處,從而讓讀者對這兩種協議有更加深入的理解。

SAML

SAML的全稱是Security Assertion Markup Language, 是由OASIS制定的一套基於XML格式的開放標準,用在身份提供者(IdP)和服務提供者 (SP)之間交換身份驗證和授權資料。

SAML的一個非常重要的應用就是基於Web的單點登入(SSO)。

在SAML協議中定義了三個角色,分別是principal:代表主體通常表示人類使用者。identity provider (IdP)身份提供者和service provider (SP)服務提供者。

IdP的作用就是進行身份認證,並且將使用者的認證資訊和授權資訊傳遞給服務提供者。

SP的作用就是進行使用者認證資訊的驗證,並且授權使用者訪問指定的資源資訊。

接下來,我們通過一個用SAML進行SSO認證的流程圖,來分析一下SAML是怎麼工作的。

上圖中User Agent就是web瀏覽器,我們看一下如果使用者想請求Service Provider的資源的時候,SAML協議是怎麼處理的。

  1. 使用者通過User Agent請求Service Provider,比如:
http://sp.flydean.com/myresource

SP將會對該資源進行相應的安全檢查,如果發現已經有一個有效的安全上下文的話,SP將會跳過2-7步,直接進入第8步。

  1. 如果在第一步的時候,SP並沒有找到相應的有效安全上下文的話,則會生成對應的SAMLRequest,並將User Agent重定向到IdP:
302 Redirect
Location: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token

RelayState是SP維護的一個狀態資訊,主要用來防止CSRF攻擊。

其中這個SAMLRequest是用Base64編碼的samlp:AuthnRequest,下面是一個samlp:AuthnRequest的例子:

  <samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="aaf23196-1773-2113-474a-fe114412ab72"
    Version="2.0"
    IssueInstant="2020-09-05T09:21:59Z"
    AssertionConsumerServiceIndex="0"
    AttributeConsumingServiceIndex="0">
    <saml:Issuer>https://sp.flydean.com/SAML2</saml:Issuer>
    <samlp:NameIDPolicy
      AllowCreate="true"
      Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
  </samlp:AuthnRequest>

為了安全起見,SAMLRequest還可以使用SP提供的簽名key來進行簽名。

  1. User agent將會傳送一個get請求到IdP的SSO server :
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1
Host: idp.flydean.com

IdP收到這個AuthnRequest請求之後,將會進行安全驗證,如果是合法的AuthnRequest,那麼將會展示登入介面。

  1. 使用者可以輸入使用者名稱密碼進行登入。登入成功之後,IdP將會返回一個XHTML form:
  <form method="post" action="https://sp.flydean.com/SAML2/SSO/POST" ...>
    <input type="hidden" name="SAMLResponse" value="response" />
    <input type="hidden" name="RelayState" value="token" />
    ...
    <input type="submit" value="Submit" />
  </form>

這個form中包含了SAMLResponse資訊,SAMLResponse中包含了使用者相關的資訊。

同樣的SAMLResponse也是使用Base64進行編碼過的samlp:Response

<samlp:Response
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="identifier_2"
    InResponseTo="identifier_1"
    Version="2.0"
    IssueInstant="2020-09-05T09:22:05Z"
    Destination="https://sp.flydean.com/SAML2/SSO/POST">
    <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer>
    <samlp:Status>
      <samlp:StatusCode
        Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion
      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
      ID="identifier_3"
      Version="2.0"
      IssueInstant="2020-09-05T09:22:05Z">
      <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer>
      <!-- a POSTed assertion MUST be signed -->
      <ds:Signature
        xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
      <saml:Subject>
        <saml:NameID
          Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
          3f7b3dcf-1674-4ecd-92c8-1544f346baf8
        </saml:NameID>
        <saml:SubjectConfirmation
          Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
          <saml:SubjectConfirmationData
            InResponseTo="identifier_1"
            Recipient="https://sp.flydean.com/SAML2/SSO/POST"
            NotOnOrAfter="2020-09-05T09:27:05Z"/>
        </saml:SubjectConfirmation>
      </saml:Subject>
      <saml:Conditions
        NotBefore="2020-09-05T09:17:05Z"
        NotOnOrAfter="2020-09-05T09:27:05Z">
        <saml:AudienceRestriction>
          <saml:Audience>https://sp.flydean.com/SAML2</saml:Audience>
        </saml:AudienceRestriction>
      </saml:Conditions>
      <saml:AuthnStatement
        AuthnInstant="2020-09-05T09:22:00Z"
        SessionIndex="identifier_3">
        <saml:AuthnContext>
          <saml:AuthnContextClassRef>
            urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
         </saml:AuthnContextClassRef>
        </saml:AuthnContext>
      </saml:AuthnStatement>
    </saml:Assertion>
  </samlp:Response>

我們可以看到samlp:Response中包含有saml:Assertion資訊。

  1. user agent 收到XHTML form之後將會提交該form給SP。

  2. SP中的assertion consumer service將會處理這個請求,建立相關的安全上下文,並將user agent重定向到要訪問的資源頁面。

  3. user agent再次請求SP資源。

  4. 因為安全上下文已經建立完畢,SP可以直接返回相應的資源,不用再次到IdP進行認證。

我們可以看到上面的所有的資訊交換都是由前端瀏覽器來完成的,在SP和IdP之間不存在直接的通訊。

這種全部由前端來完成資訊交換的方式好處就是協議流非常簡單,所有的訊息都是簡單的GET或者POST請求。

如果為了提高安全性,也可以使用引用訊息。也就是說IdP返回的不是直接的SAML assertion,而是一個SAML assertion的引用。SP收到這個引用之後,可以從後臺再去查詢真實的SAML assertion,從而提高了安全性。

SAML的缺點

SAML協議是2005年制定的,在制定協議的時候基本上是針對於web應用程式來說的,但是那時候的web應用程式還是比較簡單的,更別提對App的支援。

SAML需要通過HTTP Redect和HTTP POST協議來傳遞使用者資訊,並且通常是通過HTML FORM的格式來進行資料的提交的。如果應用程式並不是web應用,比如說是一個手機App應用。

這個手機APP應用的啟動連結是 my-photos://authenticate , 但是手機app可能並不能獲取到Http POST的body內容。他們只能夠通過URL來進行引數的傳遞。

這就意味著,在手機APP中不能夠使用SAML。

當然,要想工作也可以,不過需要進行一些改造。比如通過第三方應用對POST訊息進行解析,然後將解析出來的SAMLRequest以URL引數的形式傳遞給APP。

另一種方法就是使用OAuth2.

OAuth2

因為Oauth2是在2012年才產生的。所以並沒有那麼多的使用限制。我們可以在不同的場合中使用OAuth2。

我們先來看一下OAuth2中授權的流程圖:

一般來說OAuth2中有4個角色。

resource owner: 代表的是資源的所有者,可以通過提供使用者名稱密碼或者其他方式來進行授權。通常來是一個人。

resource server:代表的是最終需要訪問到資源的伺服器。比如github授權之後獲取到的使用者資訊。

client: 用來替代resource owner來進行互動的客戶端。

authorization server: 用來進行授權的伺服器,可以生成相應的Access Token。

整個流程是這樣的:

Client向resource owner發起一個授權請求,resource owner輸入相應的認證資訊,將authorization grant返回給client。

client再將獲取到的authorization grant請求授權伺服器,並返回access token。

client然後就可以拿著這個access token去請求resource server,最後獲取到受限資源。

OAuth2的缺點

OAuth2並沒有指定Resource Server怎麼和Authorization Server進行互動。也沒有規定返回使用者資訊的內容和格式。這些都需要實現方自己去決定。

OAuth2預設是在HTTPS環境下工作的,所以並沒有約定資訊的加密方式。我們需要自己去實現。

最後,OAuth2是一個授權協議,而不是認證協議。對於這個問題,其實我們可以考慮使用OpenID Connect協議。因為OpenID Connect就是基於OAuth2實現的,並且新增了認證協議。

OpenID Connect簡稱為OIDC,已成為Internet上單點登入和身份管理的通用標準。 它在OAuth2上構建了一個身份層,是一個基於OAuth2協議的身份認證標準協議。

OAuth2實際上只做了授權,而OpenID Connect在授權的基礎上又加上了認證。

OIDC的優點是:簡單的基於JSON的身份令牌(JWT),並且完全相容OAuth2協議。

兩者的對比

在SAML協議中,SAML token中已經包含了使用者身份資訊,但是在OAuth2,在拿到token之後,需要額外再做一次對該token的校驗。

但是另一方面,OAuth2因為需要再做一次認證,所以可以在 Authorization Server 端對token進行無效處理。

CAS簡介

做過SSO的應該都聽說過CAS。CAS的全稱是Central Authentication Service,是一個企業級的開源的SSO認證框架。

CAS內部整合了CAS1,2,3,SAML1,2,OAuth2,OpenID和OpenID Connect協議,非常的強大。我們會在後面的文章中介紹CAS的使用。

本文作者:flydean程式那些事

本文連結:http://www.flydean.com/saml-vs-oauth2/

本文來源:flydean的部落格

歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

相關文章