1. 程式人生 > >安全宣告標記語言SAML2.0初探

安全宣告標記語言SAML2.0初探

[toc] # 簡介 SAML的全稱是Security Assertion Markup Language, 是由OASIS制定的一套基於XML格式的開放標準,用在身份提供者(IdP)和服務提供者 (SP)之間交換身份驗證和授權資料。 SAML的一個非常重要的應用就是基於Web的單點登入(SSO)。 接下來我們一起來看看SAML是怎麼工作的。 # SAML的構成 在SAML協議中定義了三個角色,分別是principal:代表主體通常表示人類使用者。identity provider (IdP)身份提供者和service provider (SP)服務提供者。 IdP的作用就是進行身份認證,並且將使用者的認證資訊和授權資訊傳遞給服務提供者。 SP的作用就是進行使用者認證資訊的驗證,並且授權使用者訪問指定的資源資訊。 # SAML的優勢 為什麼要使用SAML呢? 第一可以提升使用者體驗,如果系統使用SAML,那麼可以在登入一次的情況下,訪問多個不同的系統服務。這實際上也是SSO的優勢,使用者不需要分別記住多個系統的使用者名稱和密碼,只用一個就夠了。 第二可以提升系統的安全性,使用SAML,我們只需要向IdP提供使用者名稱密碼即可, 第三使用者的認證資訊不需要儲存在所有的資源伺服器上面,只需要在在IdP中儲存一份就夠了。 # SAML是怎麼工作的 接下來,我們通過一個用SAML進行SSO認證的流程圖,來分析一下SAML是怎麼工作的。 根據請求方式有redirect和post的不同,使用SAML來進行SSO認證有通常有三種方式,我們一一道來。 ## SP redirect request; IdP POST response ![](https://img-blog.csdnimg.cn/20200917121937112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_25,color_8F8F8F,t_70) 上圖中User Agent就是web瀏覽器,我們看一下如果使用者想請求Service Provider的資源的時候,SAML協議是怎麼處理的。 1. 使用者通過User Agent請求Service Provider,比如: ~~~java http://sp.flydean.com/myresource ~~~ SP將會對該資源進行相應的安全檢查,如果發現已經有一個有效的安全上下文的話,SP將會跳過2-7步,直接進入第8步。 2. 如果在第一步的時候,SP並沒有找到相應的有效安全上下文的話,則會生成對應的SAMLRequest,並將User Agent重定向到IdP: ~~~java 302 Redirect Location: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token ~~~ RelayState是SP維護的一個狀態資訊,主要用來防止CSRF攻擊。 其中這個SAMLRequest是用Base64編碼的,下面是一個samlp:AuthnRequest的例子: ~~~xml https://sp.flydean.com/SAML2 ~~~ 為了安全起見,SAMLRequest還可以使用SP提供的簽名key來進行簽名。 3. User agent將會發送一個get請求到IdP的SSO server : ~~~shell GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1 Host: idp.flydean.com ~~~ IdP收到這個AuthnRequest請求之後,將會進行安全驗證,如果是合法的AuthnRequest,那麼將會展示登入介面。 4. 使用者可以輸入使用者名稱密碼進行登入。登入成功之後,IdP將會返回一個XHTML form: ~~~xml ... ~~~ 這個form中包含了SAMLResponse資訊,SAMLResponse中包含了使用者相關的資訊。 同樣的SAMLResponse也是使用Base64進行編碼過的。 ~~~xml
https://idp.flydean.com/SAML2 https://idp.flydean.com/SAML2 ... 3f7b3dcf-1674-4ecd-92c8-1544f346baf8 https://sp.flydean.com/SAML2 urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
~~~ 我們可以看到samlp:Response中包含有saml:Assertion資訊。 5. user agent 收到XHTML form之後將會提交該form給SP。 6. SP中的assertion consumer service將會處理這個請求,建立相關的安全上下文,並將user agent重定向到要訪問的資源頁面。 7. user agent再次請求SP資源。 8. 因為安全上下文已經建立完畢,SP可以直接返回相應的資源,不用再次到IdP進行認證。 我們可以看到上面的所有的資訊交換都是由前端瀏覽器來完成的,在SP和IdP之間不存在直接的通訊。 這種全部由前端來完成資訊交換的方式好處就是協議流非常簡單,所有的訊息都是簡單的GET或者POST請求。 如果為了提高安全性,也可以使用引用訊息。也就是說IdP返回的不是直接的SAML assertion,而是一個SAML assertion的引用。SP收到這個引用之後,可以從後臺再去查詢真實的SAML assertion,從而提高了安全性。 ## SP POST Request; IdP POST Response 剛剛講的是SP redirect Request,這裡我們看一下SP POST request是怎麼做的: ![](https://img-blog.csdnimg.cn/20200917153700878.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_25,color_8F8F8F,t_70) 和第一種方式的不同之處在於第二步和第三步。 第二步:SP不再進行redirect了,而是返回一個XHTML form給User agent: ~~~xml ... ~~~ 第三步:拿到第二步的XHTML form之後,User agent將該form post到IdP SSO server。 從第四步開始就和第一種方式是一樣的了。 ## SP redirect artifact; IdP redirect artifact 第三種方式,SP和IdP都用的是redirect,但是redirect的內容都是artifact。 之前我們講了SAML message可以以值的方式也可以以引用的方式來進行傳遞。 而這種以引用的傳遞方式就是artifact。 收到artifact的receiver會發送一個 給issuer,從而獲得真正的message。 下面是一個向IdP請求message的例子: ~~~xml https://idp.flydean.com/SAML2
... AAQAAMh48/1oXIM+sDo7Dh2qMp1HM4IF5DaRNmDj6RdUmllwn9jJHyEgIi8=
~~~ 相應的server會返回一個包含: ~~~xml ... https://sp.flydean.com/SAML2 ~~~ 看下第三種方式的流程圖: ![](https://img-blog.csdnimg.cn/20200917165041746.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_25,color_8F8F8F,t_70) 可以看到這種方式和前面兩種方式的區別就是多了一個請求真實message的步驟。 以第三,四,五步為例: 第三步user agent請求IdP的SSO server: ~~~java https://idp.example.org/SAML2/SSO/Artifact?SAMLart=artifact_1&RelayState=token ~~~ 注意這裡請求的引數變成了SAMLart。 第四步,IdP需要傳送一個到SP來請求真正的samlp:AuthnRequest。 第五步,SP返回一個 包含samlp:AuthnRequest。 # 總結 SAML協議和它的基本用法就是上面這樣。下面的文章我們會舉一個具體的例子,來講解如何應用SAML協議。 > 本文作者:flydean程式那些事 > > 本文連結:[http://www.flydean.com/saml-startup/](http://www.flydean.com/saml-startup/) > > 本文來源:flydean的部落格 > > 歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!