SAML是一種目前應(yīng)用非常廣泛的單點(diǎn)登錄協(xié)議,如果你運(yùn)行SAML服務(wù)器并與許多其他站點(diǎn)集成,那么幾乎可以肯定你使用的是不安全的設(shè)置。SAML安全面臨的最大威脅不是怪異的XML邊緣案例或黑客竊取你的簽名密鑰,而是低質(zhì)量的第三方實(shí)現(xiàn),這允許你的用戶(hù)登錄到你認(rèn)為他們無(wú)法訪問(wèn)的應(yīng)用程序。要確保SAML斷言只適用于正確的應(yīng)用程序,請(qǐng)為每個(gè)應(yīng)用程序或服務(wù)提供者使用惟一的簽名密鑰。
這個(gè)問(wèn)題并不是SAML獨(dú)有的,簽名的JWT和其他SSO的使用(比如OIDC中的使用)也可能遇到類(lèi)似的問(wèn)題,即缺少令牌驗(yàn)證。
SAML是如何工作的?
從較高的層次上講,SAML是一種登錄用戶(hù)的方式,它使用兩個(gè)系統(tǒng)之間的瀏覽器內(nèi)部通信,否則它們之間不能相互通信。當(dāng)用戶(hù)想要登錄到他們最喜歡的SaaS時(shí),SaaS應(yīng)用程序(SP或服務(wù)提供商)會(huì)將一些關(guān)于登錄請(qǐng)求的數(shù)據(jù)發(fā)送到你的IDP。這包括諸如惟一請(qǐng)求ID和數(shù)據(jù)(如你試圖訪問(wèn)的原始頁(yè)面)之類(lèi)的內(nèi)容。理論上,身份驗(yàn)證請(qǐng)求可以指定IDP應(yīng)該返回哪種類(lèi)型的用戶(hù)名和名稱(chēng)之類(lèi)的字段,但實(shí)際上這會(huì)被忽略。這些請(qǐng)求也可以簽名,但實(shí)際上在SP旋轉(zhuǎn)其密鑰時(shí),大多數(shù)情況都會(huì)使事情中斷。安全性幾乎沒(méi)有好處,因?yàn)樵谌魏维F(xiàn)代系統(tǒng)中,SAML交換都是通過(guò)TLS進(jìn)行的。
SAML是一種目前應(yīng)用非常廣泛的單點(diǎn)登錄協(xié)議,如果你運(yùn)行SAML服務(wù)器并與許多其他站點(diǎn)集成,那么幾乎可以肯定你使用的是不安全的設(shè)置。SAML安全面臨的最大威脅不是怪異的XML邊緣案例或黑客竊取你的簽名密鑰,而是低質(zhì)量的第三方實(shí)現(xiàn),這允許你的用戶(hù)登錄到你認(rèn)為他們無(wú)法訪問(wèn)的應(yīng)用程序。要確保SAML斷言只適用于正確的應(yīng)用程序,請(qǐng)為每個(gè)應(yīng)用程序或服務(wù)提供者使用惟一的簽名密鑰。
這個(gè)問(wèn)題并不是SAML獨(dú)有的,簽名的JWT和其他SSO的使用(比如OIDC中的使用)也可能遇到類(lèi)似的問(wèn)題,即缺少令牌驗(yàn)證。
SAML是如何工作的?
從較高的層次上講,SAML是一種登錄用戶(hù)的方式,它使用兩個(gè)系統(tǒng)之間的瀏覽器內(nèi)部通信,否則它們之間不能相互通信。當(dāng)用戶(hù)想要登錄到他們最喜歡的SaaS時(shí),SaaS應(yīng)用程序(SP或服務(wù)提供商)會(huì)將一些關(guān)于登錄請(qǐng)求的數(shù)據(jù)發(fā)送到你的IDP。這包括諸如惟一請(qǐng)求ID和數(shù)據(jù)(如你試圖訪問(wèn)的原始頁(yè)面)之類(lèi)的內(nèi)容。理論上,身份驗(yàn)證請(qǐng)求可以指定IDP應(yīng)該返回哪種類(lèi)型的用戶(hù)名和名稱(chēng)之類(lèi)的字段,但實(shí)際上這會(huì)被忽略。這些請(qǐng)求也可以簽名,但實(shí)際上在SP旋轉(zhuǎn)其密鑰時(shí),大多數(shù)情況都會(huì)使事情中斷。安全性幾乎沒(méi)有好處,因?yàn)樵谌魏维F(xiàn)代系統(tǒng)中,SAML交換都是通過(guò)TLS進(jìn)行的。
一旦你的IDP接收到身份驗(yàn)證請(qǐng)求,IDP將驗(yàn)證你是否已登錄(可能是密碼、可能是客戶(hù)端證書(shū)),然后簽署一個(gè)斷言。斷言是SP將驗(yàn)證并用于登錄你的內(nèi)容。然后,你的IDP將此斷言發(fā)送回SP。SP驗(yàn)證密碼簽名,驗(yàn)證該斷言是否應(yīng)該發(fā)送到特定的SP,并提取相關(guān)的用戶(hù)名和其他字段?,F(xiàn)在,你可以看所有你想看的圖片了!
那個(gè)簽名秘鑰聽(tīng)起來(lái)很?chē)樔?!你的本能可能是不惜一切代價(jià)保護(hù)該密鑰。密鑰值得保護(hù),但是對(duì)你的SAML IDP安全最大的可信威脅不是擁有你的SAML服務(wù)器的攻擊者。
攻擊SAML的方法
攻擊SAML的方法有很多!盡管獨(dú)特的簽名密鑰可以解決其中的一些問(wèn)題,但這并不是萬(wàn)能的。
受眾限制問(wèn)題(Audience restriction issue)
這是我在這篇文章中關(guān)注的問(wèn)題,稍后我將更詳細(xì)地討論它。不出意料,惟一簽名密鑰解決了這類(lèi)問(wèn)題。
IDP簽名密鑰被盜
確實(shí),能夠訪問(wèn)你的IDP的人可以獲得簽名密鑰的副本,并以任何人的身份登錄到與你集成的任何網(wǎng)站。如果這是你所關(guān)心的威脅,則僅提供簽名預(yù)言的硬件支持的密鑰是正確的防御措施。
XML和XML安全庫(kù)
如果可以的話,你應(yīng)該使用一個(gè)內(nèi)存安全的庫(kù)。也就是說(shuō),這對(duì)第三方的斷言驗(yàn)證沒(méi)有實(shí)際影響,而且如果使用惟一簽名密鑰,你的安全狀態(tài)也不會(huì)改變。
XML處理問(wèn)題
XML安全性是本世紀(jì)初出現(xiàn)的一種內(nèi)聯(lián)簽名格式,當(dāng)時(shí)沒(méi)有人提出要求,需要它的人也更少。但用的人多了,問(wèn)題就出現(xiàn)了,這些問(wèn)題包括,忽略用戶(hù)名中的XML注釋、簽名格式本身忽略對(duì)XML解析器有影響的注釋?zhuān)约安粰z查你驗(yàn)證的簽名是否實(shí)際覆蓋了你信任的所有數(shù)據(jù)。
你可以通過(guò)使用惟一的簽名密鑰來(lái)減小這些問(wèn)題的影響范圍。你只需要關(guān)心單個(gè)應(yīng)用程序的內(nèi)部權(quán)限,而不是允許用戶(hù)登錄任何與你集成的服務(wù)(授權(quán)與否)。
解決方案
核心問(wèn)題是缺乏受眾限制驗(yàn)證,換句話說(shuō),SP沒(méi)有檢查斷言是否針對(duì)它。SAML的設(shè)計(jì)思想是你的IDP將只有一個(gè)簽名密鑰,你可以將它分發(fā)給與你集成的每個(gè)人??紤]到SAML的學(xué)術(shù)背景,它應(yīng)該是一個(gè)合作協(xié)議,組織之間密切合作。現(xiàn)代企業(yè)SAML忽略了所有這些有趣的特性,因?yàn)樗鼈兪蔷薮蟮陌踩团渲秘瑝?mèng)。
當(dāng)你的IDP簽署一個(gè)斷言時(shí),它包含兩個(gè)供SP驗(yàn)證的字段:SP的實(shí)體ID和斷言要發(fā)送到的URL。SP可以悄悄地忽略這些字段,而你對(duì)此無(wú)能為力。
作為負(fù)責(zé)簽名密鑰的IDP,你如何保護(hù)自己免受不可避免的弱SP攻擊?
處理一堆簽名鑰匙
相比依賴(lài)協(xié)議的某些部分,唯一可擴(kuò)展的方法是強(qiáng)制你的斷言?xún)H在一個(gè)SP上有效,而且是通過(guò)具有唯一簽名每個(gè)SP的密鑰。
之所以可行,是因?yàn)閹缀趺總€(gè)SAML SP實(shí)現(xiàn)都包含三個(gè)部分。他們將從請(qǐng)求中提取用戶(hù)名,在斷言中驗(yàn)證簽名,并拒絕無(wú)效的斷言簽名,其他所有內(nèi)容都應(yīng)視為可選內(nèi)容。
雖然SP可以忽略你的簽名,但是它的測(cè)試超級(jí)簡(jiǎn)單,而且這種事情很容易被漏洞賞金報(bào)告人員發(fā)現(xiàn)。與更深?yuàn)W的受眾限制測(cè)試不同,這里不涉及任何復(fù)雜性。
如何管理這么多密鑰?
過(guò)去,我通過(guò)編寫(xiě)一堆Ruby自動(dòng)生成相關(guān)XML來(lái)處理每個(gè)SP的唯一簽名密鑰,從而為Shibboleth管理了多個(gè)密鑰。每當(dāng)我遇到另一個(gè)錯(cuò)誤處理斷言的SP時(shí),我都會(huì)感謝為減少這個(gè)我們不得不擔(dān)心的問(wèn)題而付出的努力。
在理想的情況下,我們不會(huì)使用SAML。 SAML是一種繁瑣的協(xié)議,可讓你創(chuàng)建帶有身份驗(yàn)證內(nèi)聯(lián)簽名的身份提供者的網(wǎng)狀網(wǎng)絡(luò),其中XML中的空格確定簽名是否有效。但是SAML以及OAuth 2.0和不完美的OIDC都將保留下來(lái)。鑒于SAML是事實(shí)上的企業(yè)單一登錄協(xié)議,我們將忽略它。
如果你的IDP不支持此功能(請(qǐng)參見(jiàn)下文),則應(yīng)向他們打開(kāi)功能請(qǐng)求!這是你的IDP應(yīng)該支持的重要安全控制。
如果你的IDP確實(shí)支持這個(gè)功能,為你的新應(yīng)用程序發(fā)出每個(gè)sp的簽名密鑰。使用舊的證書(shū)遷移應(yīng)用程序需要做很多工作,但是如果你有特別敏感的應(yīng)用程序,則值得這樣做。
所有SaaS IDP都應(yīng)在沒(méi)有任何用戶(hù)干預(yù)的情況下生成每個(gè)應(yīng)用程序的簽名密鑰,默認(rèn)情況下,每個(gè)SP密鑰的使用率極高,可以悄悄地提高與這些提供商簽約的每個(gè)企業(yè)的安全性。截至2020年3月,唯一獲得此權(quán)限的提供商是Azure AD。
自托管的IDP應(yīng)確保它們支持按SP的簽名密鑰,并具有啟用此功能的文檔。理想情況下,共享簽名密鑰的配置不太明顯,因此管理員默認(rèn)情況下選擇每個(gè)SP的簽名密鑰。
雖然最終要由SSO管理員做出正確的SSO選擇,但是我們作為安全行業(yè)的責(zé)任是使正確的選擇變得容易。
IDP支持多個(gè)簽名密鑰
沒(méi)有實(shí)施指南,最佳做法將無(wú)濟(jì)于事。這是截至2020年3月我已測(cè)試的各種主要IDP(包括SaaS和自托管選項(xiàng))的列表。如果你的首選IDP不在此列表中或條目不正確,請(qǐng)與我們聯(lián)系。
Azure AD – SaaS
Azure AD自動(dòng)為每個(gè)“企業(yè)應(yīng)用程序”生成一個(gè)新密鑰,并且無(wú)法在控制臺(tái)中的應(yīng)用程序之間共享證書(shū)。你可以手動(dòng)上傳自己的證書(shū)和私鑰,但這并不容易,我也不鼓勵(lì)這樣做,Azure AD應(yīng)該是所有其他SaaS IDP的模型。
Shibboleth - Java(自托管)
你必須編寫(xiě)大量的XML才能使它工作,如果你花了幾個(gè)小時(shí)絞盡腦汁地研究Spring XML配置,就不會(huì)出現(xiàn)任何問(wèn)題。我已經(jīng)包括了基本的需求。要點(diǎn)是,你需要?jiǎng)?chuàng)建單獨(dú)的簽名憑據(jù),包括安全配置中的簽名憑據(jù),然后從單獨(dú)的SP引用該安全配置。
另外,我確實(shí)喜歡Shibboleth是全java的狀態(tài),即沒(méi)有內(nèi)存損壞!,可以在本地自己的服務(wù)器上運(yùn)行,并且采用非常符合標(biāo)準(zhǔn)的方法,從而降低了被奇怪的XML問(wèn)題影響的可能性。
conf/relying-party.xml的示例配置(Shibboleth文檔):
conf/credentials.xml的示例配置(Shibboleth文檔):
PingOne—SaaS
這不是默認(rèn)的,因?yàn)樵谀J(rèn)情況下,PingOne使用一個(gè)共享簽名密鑰。有一個(gè)單獨(dú)的證書(shū)頁(yè)面,你可以在其中創(chuàng)建新的證書(shū)。添加一些內(nèi)容后,你可以將每個(gè)SAML“應(yīng)用程序”配置為使用唯一的簽名密鑰。
OneLogin—SaaS
這不是默認(rèn)的,因?yàn)樵谀J(rèn)情況下,OneLogin使用一個(gè)共享簽名密鑰。你可以嘗試在單個(gè)SAML配置的設(shè)置中更改此秘鑰,但不能添加新的秘鑰。你必須導(dǎo)航到單獨(dú)的“證書(shū)”頁(yè)面以創(chuàng)建新證書(shū),但是一旦完成,就可以為每個(gè)SP創(chuàng)建唯一的簽名密鑰。
一旦添加了“證書(shū)”(實(shí)際上是一個(gè)簽名密鑰),就可以將它分配給任意的SP。
Okta—SaaS
是的,但是需要在API中進(jìn)行修改。Okta為每個(gè)SP使用不同的實(shí)體ID,但是默認(rèn)情況下,使用完全相同的憑據(jù)對(duì)聲明進(jìn)行簽名。無(wú)法在Okta控制臺(tái)中上傳自定義私鑰或旋轉(zhuǎn)簽名憑證。
但是,你可以創(chuàng)建一個(gè)新的簽名密鑰,并通過(guò)兩個(gè)API調(diào)用將密鑰與應(yīng)用程序關(guān)聯(lián)。
GSuite SAML - SaaS
GSuite的SAML配置允許你在給定的時(shí)間內(nèi)擁有兩個(gè)簽名證書(shū),這樣你就可以旋轉(zhuǎn)過(guò)期的簽名證書(shū)。很明顯,GSuite可以支持其他證書(shū),但它不支持。
Auth0——SaaS
盡管支持唯一的OAuth 2.0客戶(hù)端機(jī)密,但Auth0在所有SAML“應(yīng)用程序”之間共享一個(gè)簽名證書(shū)!也沒(méi)有選擇旋轉(zhuǎn)你的SAML簽名憑據(jù)。鑒于你正在動(dòng)態(tài)配置每個(gè)SP,因此沒(méi)有理由不生成每個(gè)SP的簽名憑據(jù)。
ADFS - Microsoft Windows Server(自托管)
Windows Server 2019版的ADFS不支持每個(gè)“依賴(lài)方”(我們稱(chēng)之為SP)的唯一“簽名令牌”。在運(yùn)行一些PowerShell以禁用自動(dòng)旋轉(zhuǎn)之后,你可以手動(dòng)添加一個(gè)用于旋轉(zhuǎn)的備用證書(shū),但它對(duì)其他任何東西都沒(méi)有用處。
在每個(gè)SP上運(yùn)行一個(gè)ADFS服務(wù)器并在每個(gè)服務(wù)器上使用單獨(dú)的簽名令牌在技術(shù)上是可行的。這將是痛苦的管理,更不用說(shuō)Windows許可成本,所以我不認(rèn)為這是一個(gè)好的建議。
Gluu——自托管
Gluu的用戶(hù)界面未提供任何將特定簽名身份與SAML SP相關(guān)聯(lián)的方法,也無(wú)法創(chuàng)建新的簽名身份。
Duo Access Gateway –自托管
根據(jù)通用SP配置的文檔,整個(gè)DAG服務(wù)器只有一個(gè)證書(shū)。你可以重新創(chuàng)建證書(shū),但這似乎會(huì)影響到?jīng)]有唯一密鑰選項(xiàng)的每個(gè)SP。
SimpleSAMLphp—自托管
SimpleSAMLphp的IDP支持單個(gè)服務(wù)提供者的唯一密鑰,一旦你知道要查找什么,它就很簡(jiǎn)單了。在“SP遠(yuǎn)程元數(shù)據(jù)”參考中,通過(guò)signature.certificate和signature.privatekey可以為每個(gè)SP指定一個(gè)單獨(dú)的密鑰。
雖然它確實(shí)很好地支持惟一秘鑰,但如果可以的話,你最好不要使用這個(gè)軟件。該項(xiàng)目有一個(gè)經(jīng)典的PHP webapp漏洞。
總結(jié)
1. 有一些深?yuàn)W的功能,例如動(dòng)態(tài)ACS(斷言消費(fèi)者服務(wù))URL,還有可能會(huì)被誤用的功能,例如通過(guò)未加密的HTTP提供元數(shù)據(jù),但是同樣,在現(xiàn)代公司SAML中,TLS至關(guān)重要。
2. 我不相信libxmlsec1庫(kù),尤其是libxml2庫(kù)。這兩個(gè)C庫(kù)都非常常用,沒(méi)有真正的替代方法。如果你認(rèn)為使用Ruby,PHP或Python SAML庫(kù)是安全的,那么你就錯(cuò)了,它們都依賴(lài)于libxmlsec1。
3. 盡管C庫(kù)為我們服務(wù)了很多年,但到2020年,由于內(nèi)存損壞問(wèn)題嚴(yán)重,它將成為安全負(fù)擔(dān)。libxml2的漏洞歷史可以追溯到2004年(16年前!)。雖然libxmlsec1沒(méi)有相同的記錄歷史,但我懷疑只是由于缺少必要的報(bào)告,而不是真的沒(méi)有內(nèi)存安全問(wèn)題。通過(guò)對(duì)已知漏洞進(jìn)行相對(duì)快速的修補(bǔ)來(lái)積極地維護(hù)這些庫(kù),可以在一定程度上緩解這種危險(xiǎn),但是如果可以的話,我不會(huì)使用這些庫(kù)。
4. 就我個(gè)人而言,我認(rèn)為對(duì)于安全界的外行來(lái)說(shuō),進(jìn)入的門(mén)檻是相當(dāng)高的!你必須與第三方進(jìn)行有效的SSO集成,并且必須能夠訪問(wèn)私鑰(我們已經(jīng)不太可能使用它了)或能夠更改部分?jǐn)嘌裕ㄈ缬脩?hù)名)。大多數(shù)IDP都不愿意讓你更改字段,因?yàn)樗鼈兪菑哪銦o(wú)權(quán)訪問(wèn)的中央目錄中提取的。即使確實(shí)滿足所有這些條件,這些漏洞通常也只能讓你在現(xiàn)有組織中橫向移動(dòng),而不能完全以其他帳戶(hù)身份登錄。
5. 接受不同組織的斷言實(shí)際上是一件非??膳碌氖虑椋?yàn)樽鳛镮DP,你幾乎無(wú)能為力。保護(hù)自己不受攻擊的最好方法是測(cè)試SP是否有這種行為。不過(guò),我在本文中沒(méi)有深入探討這個(gè)問(wèn)題,
6. Gluu是基于Shibboleth的,因此你可以手動(dòng)設(shè)置一個(gè)工作配置,這可能會(huì)破壞UI。