對(duì)于一個(gè)安全的應(yīng)用來(lái)說(shuō),身份驗(yàn)證是第一道門(mén)檻,是與用戶(hù)建立數(shù)字信任關(guān)系的基礎(chǔ)部分,現(xiàn)代的身份管理系統(tǒng)可以自動(dòng)收集有關(guān)用戶(hù)的信息,驗(yàn)證他們的身份是否與他們的實(shí)際身份相符,并允許他們的注冊(cè)或訪問(wèn)請(qǐng)求,從而創(chuàng)建了一種不會(huì)影響用戶(hù)體驗(yàn)的安全身份驗(yàn)證功能。
根據(jù) Javelin 2020 年身份欺詐調(diào)查,2019 年身份欺詐的總成本接近 170 億美元,現(xiàn)在這個(gè)數(shù)字更高。由于這些非常真實(shí)的風(fēng)險(xiǎn),可靠地驗(yàn)證用戶(hù)身份的能力是安全基礎(chǔ)設(shè)施的關(guān)鍵組成部分。
為了對(duì)那些有安全需求的特定資源進(jìn)行訪問(wèn)控制,只讓某些特定的主體(個(gè)人、公司、甚至是一段代碼)對(duì)其執(zhí)行某些特定的操作(查看、修改等)。需要按照順序達(dá)成如下兩個(gè)條件:
1、認(rèn)證(Authentication):知道 ta 究竟是誰(shuí)
2、授權(quán)(Authorization):知道 ta 有沒(méi)有權(quán)限對(duì)資源執(zhí)行試圖執(zhí)行的操作
認(rèn)證是決定一個(gè)主體究竟是誰(shuí)的過(guò)程,換句話來(lái)說(shuō),是將當(dāng)前意圖訪問(wèn)資源的用戶(hù)和提前存儲(chǔ)好的身份信息對(duì)應(yīng)起來(lái)的過(guò)程。顯然,這個(gè)操作需要由身份信息的持有者來(lái)完成,我們稱(chēng)其為IdP(Identity Provider),它存儲(chǔ)的身份信息列表稱(chēng)為用戶(hù)目錄或用戶(hù)池。所謂的身份信息可以是任意格式,包含但不限于以下兩種內(nèi)容:用戶(hù)的唯一標(biāo)識(shí)符(可以是唯一的用戶(hù)名、隨機(jī)字符串、UUID 等),以及只有該用戶(hù)才能提供,用來(lái)確認(rèn)該用戶(hù)身份的私密信息(密碼、指紋等)。前者可以是公開(kāi)的,但后者必須是私密的,只有 IdP 和用戶(hù)自身才能持有。
為了完成認(rèn)證,用戶(hù)必須首先宣稱(chēng)自己是誰(shuí),并且這個(gè)宣稱(chēng)需要以某種形式和用戶(hù)目錄中的唯一一條記錄產(chǎn)生關(guān)聯(lián)。顯然,最簡(jiǎn)單的辦法就是直接向 IdP 宣布自己的唯一標(biāo)識(shí)符。之后,用戶(hù)需要通過(guò)某種保密的途徑悄悄告訴 IdP 自己的私密信息,IdP 確認(rèn)無(wú)誤后,就可以將當(dāng)前正在進(jìn)行請(qǐng)求的用戶(hù)和用戶(hù)目錄中的身份信息對(duì)應(yīng)起來(lái),如此一來(lái),用戶(hù)在 IdP 上的認(rèn)證過(guò)程就完成了。
確認(rèn)了用戶(hù)的身份之后,下一步就是確認(rèn)用戶(hù)到底有沒(méi)有權(quán)限訪問(wèn)想要訪問(wèn)的資源了。擁有身份信息后,這一步就變得很簡(jiǎn)單了——只需根據(jù)對(duì)應(yīng)資源的權(quán)限設(shè)置,檢查用戶(hù)的對(duì)應(yīng)操作是否被允許即可。
在最簡(jiǎn)單的身份模型中,身份持有者(IdP)和資源持有者運(yùn)行在同一個(gè)上下文中。這意味著一旦 IdP 完成了某個(gè)用戶(hù)的認(rèn)證,資源持有者立刻就能知道(例如通過(guò)數(shù)據(jù)庫(kù)查詢(xún))用戶(hù)的身份信息。之后用戶(hù)訪問(wèn)資源時(shí),資源持有者就能利用這一信息來(lái)決定是否允許用戶(hù)的操作(相當(dāng)于自己執(zhí)行授權(quán)),或者把這一決定交給 IdP 來(lái)做(相當(dāng)于 IdP 執(zhí)行授權(quán))。這種模型的缺點(diǎn)顯而易見(jiàn)——每個(gè)應(yīng)用都要維護(hù)一套自己的用戶(hù)目錄,不同應(yīng)用之間無(wú)法共享身份信息。為了解決這個(gè)問(wèn)題,一個(gè)自然的想法就是將 IdP 獨(dú)立出來(lái),讓所有資源持有者都從 IdP 處獲取用戶(hù)的身份。這種做法存在一個(gè)前提條件:當(dāng)一個(gè)用戶(hù)在 IdP 上完成了認(rèn)證之后,資源持有者必須得知這一點(diǎn),并能從 IdP 處獲取用戶(hù)對(duì)應(yīng)的身份信息,而且這一渠道必須是可信的,身份信息不能被惡意篡改。在實(shí)際應(yīng)用中,資源持有者一般會(huì)在用戶(hù)訪問(wèn)資源時(shí),向 IdP 獲取用戶(hù)的認(rèn)證狀態(tài)和身份信息。如果成功,之后的授權(quán)步驟就和上面一致了。獨(dú)立的 IdP 有一個(gè)天然的好處——只要用戶(hù)在 IdP 上進(jìn)行過(guò)了認(rèn)證,其下關(guān)聯(lián)的所有資源持有者都能獲取到用戶(hù)的身份信息,正所謂一次認(rèn)證,到處訪問(wèn)。所謂的單點(diǎn)登錄(SSO)本質(zhì)上就是如此。由于 Web 應(yīng)用天生的無(wú)狀態(tài)性,資源持有者并不能確定訪問(wèn)資源的用戶(hù)和在 IdP 上認(rèn)證過(guò)的用戶(hù)是同一個(gè),因此用戶(hù)每次訪問(wèn)資源時(shí)都需要提供身份標(biāo)識(shí)符和密碼,由資源持有者向 IdP 進(jìn)行確認(rèn)。為了解決這一問(wèn)題,IdP 在完成認(rèn)證時(shí)可以向用戶(hù)頒發(fā)一個(gè)臨時(shí)的令牌(Token),這個(gè) Token 存儲(chǔ)著用戶(hù)目錄中的用戶(hù)身份,只有用戶(hù)本人才能持有,并且經(jīng)過(guò) IdP 的數(shù)字簽名。用戶(hù)訪問(wèn)資源時(shí),通過(guò) Cookie 等手段自動(dòng)向持有者提供 Token,持有者可以在本地利用簽名驗(yàn)證 Token 的真實(shí)性和有效性,并且從 Token 中獲取到用戶(hù)的身份信息,無(wú)需再經(jīng)過(guò) IdP 了。為了防止 Token 從用戶(hù)處泄露,它只在短時(shí)間內(nèi)有效,失效后必須由 IdP 重新頒發(fā)。最著名的 Token 技術(shù)是JWT(Json Web Token),它也是 OIDC 協(xié)議的一部分。除此之外,SAML 協(xié)議中的斷言(Assertion)也可以起到和 Token 相同的作用。當(dāng)然,用戶(hù)的登錄態(tài)也可以由資源提供者來(lái)維護(hù),資源提供者在向 IdP 確認(rèn)用戶(hù)身份后自己向用戶(hù)頒發(fā)一個(gè)類(lèi)似的 Token,存放在用戶(hù) Cookie 中。此時(shí)的 Token 可以實(shí)際存儲(chǔ)身份信息并進(jìn)行簽名,也可以作為一個(gè)索引的 Key,指向存放在資源提供者后端的,從 IdP 處獲得的身份信息(也就是所謂的 Session)。值得注意的是,在分離模型中,如果授權(quán)步驟由 IdP 執(zhí)行,用戶(hù)在 IdP 上進(jìn)行授權(quán)時(shí)還需要提供自己想要訪問(wèn)的資源種類(lèi)和執(zhí)行的操作,IdP 簽發(fā) Token 時(shí)也需要將這些信息寫(xiě)在 Token 中,以便資源持有者核驗(yàn)。資源和操作的二元組被稱(chēng)為Scope,OIDC 登錄時(shí)傳人的其中一個(gè)參數(shù)就是它。
由于Header和Payload是通過(guò)base64編碼的,因此如果敏感信息處理不到會(huì)導(dǎo)致泄露風(fēng)險(xiǎn)。簽名算法可被修改為none(CVE-2015-2951)也就是header中的“alg”為none,在線工具jwt.io無(wú)法修改,使用Pyjwt庫(kù)進(jìn)行修改,生成的jwt token只有header和payload兩部分,沒(méi)有signature:String encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);String token = HMACSHA256(encodedString, 'secret');jwt利用算法對(duì)header和payload進(jìn)行加密生成signature,如果能知道密鑰secret就能隨意修改jwt token了;jwk ,json web key,就是header中的密鑰,通過(guò)偽造header中的密鑰來(lái)控制jwt token的生成:
身份驗(yàn)證繞過(guò)漏洞是現(xiàn)代web應(yīng)用程序中普遍存在的漏洞,也是隱藏最深很難被發(fā)現(xiàn)的漏洞。盡管單點(diǎn)登錄(SSO)等工具是對(duì)舊的登錄用戶(hù)方式的改進(jìn),但仍然可能包含嚴(yán)重的漏洞。無(wú)論是業(yè)務(wù)邏輯錯(cuò)誤還是其他軟件漏洞,都需要專(zhuān)業(yè)人員來(lái)分析其中的復(fù)雜性。
在這種情況下,一旦用戶(hù)使用有效憑證登錄到應(yīng)用程序,它就會(huì)創(chuàng)建一個(gè)在應(yīng)用程序其他地方使用的承載身份驗(yàn)證令牌。該認(rèn)證令牌在一段時(shí)間后過(guò)期。就在過(guò)期之前,應(yīng)用程序在終端/refresh/tokenlogin中向后端服務(wù)器發(fā)送了一個(gè)請(qǐng)求,該請(qǐng)求在標(biāo)頭和HTTP主體部分的用戶(hù)名參數(shù)中包含有效的身份驗(yàn)證令牌。進(jìn)一步的測(cè)試表明,刪除請(qǐng)求上的Authorization標(biāo)頭并更改HTTP主體上的用戶(hù)名參數(shù)將為提供的用戶(hù)名創(chuàng)建一個(gè)新的有效令牌。利用此漏洞,擁有匿名配置文件的攻擊者可以通過(guò)提供用戶(hù)名為任何用戶(hù)生成身份驗(yàn)證令牌。
大多數(shù)應(yīng)用程序都使用SSO系統(tǒng),因?yàn)榕c處理許多身份驗(yàn)證門(mén)戶(hù)相比,SSO系統(tǒng)更容易安全管理。但是簡(jiǎn)單地使用SSO并不能自動(dòng)保護(hù)系統(tǒng),因?yàn)镾SO的配置也應(yīng)得到保護(hù)。現(xiàn)在,一個(gè)應(yīng)用程序使用Microsoft SSO系統(tǒng)進(jìn)行身份驗(yàn)證。當(dāng)訪問(wèn)internal.redacted.com URL時(shí),web瀏覽器會(huì)重定向到單點(diǎn)登錄系統(tǒng):乍一看,它似乎是安全的,但對(duì)后端請(qǐng)求的分析顯示,應(yīng)用程序在重定向響應(yīng)上返回了異常大的內(nèi)容長(zhǎng)度(超過(guò)40000字節(jié))為什么應(yīng)用程序要這樣做呢?當(dāng)然是配置錯(cuò)誤。在將用戶(hù)發(fā)送到SSO的重定向時(shí),應(yīng)用程序向每個(gè)請(qǐng)求泄露了其內(nèi)部響應(yīng)。因此,可以篡改響應(yīng),將302 Found頭更改為200 OK,并刪除整個(gè)Location標(biāo)頭,從而獲得對(duì)整個(gè)應(yīng)用程序的訪問(wèn)。
內(nèi)容管理系統(tǒng)(CMS),如WordPress、Drupal和Hubspot也需要進(jìn)行安全配置,以免它們?cè)谑褂弥幸肼┒础?/section>在發(fā)現(xiàn)的一個(gè)示例中,一個(gè)內(nèi)部應(yīng)用程序中使用了一個(gè)流行的CMS平臺(tái)Liferay。該應(yīng)用程序只有一個(gè)不需要身份驗(yàn)證就可以訪問(wèn)的登錄頁(yè)面,所有其他頁(yè)面都在應(yīng)用程序UI中受到限制。對(duì)于那些不熟悉Liferay的人來(lái)說(shuō),CMS為應(yīng)用程序工作流使用了portlet,它的參數(shù)是數(shù)字中的p_p_id。對(duì)于該應(yīng)用程序,可以通過(guò)將參數(shù)值更改為58來(lái)訪問(wèn)登錄portlet。在正常的登錄頁(yè)面中,只有登錄表單是可訪問(wèn)的。然而,通過(guò)直接訪問(wèn)portlet,可以達(dá)到Create Account功能,然后在不需要適當(dāng)?shù)氖跈?quán)情況下就可以進(jìn)行自注冊(cè)并訪問(wèn)內(nèi)部應(yīng)用程序。請(qǐng)注意,雖然Liferay以前使用過(guò)這個(gè)工作流,但它的最新版本使用了portlet名稱(chēng)而不是數(shù)字ID。不過(guò),也可以通過(guò)更改名稱(chēng)來(lái)訪問(wèn)其他portlet。
JWT令牌或JSON web令牌,在新的web應(yīng)用程序中很流行。但是,雖然它們默認(rèn)具有安全機(jī)制,但后端服務(wù)器配置也應(yīng)該是安全的。然而,一些JS文件不需要身份驗(yàn)證就可以訪問(wèn)。測(cè)試顯示,該應(yīng)用程序使用了安全登錄后通過(guò)Microsoft SSO系統(tǒng)發(fā)送的JWT令牌。在后端機(jī)制上,存在一個(gè)安全錯(cuò)誤配置,即不檢查是否為特定的應(yīng)用程序生成了JWT令牌。相反,它接受任何具有有效簽名的JWT令牌。因此,使用來(lái)自微軟網(wǎng)站的JWT令牌示例如下:有可能訪問(wèn)內(nèi)部終端,泄露公司數(shù)據(jù)。
在此情況中,應(yīng)用程序通過(guò) base64 編碼的 XML 請(qǐng)求向 HTTP 發(fā)布數(shù)據(jù)上發(fā)送所有請(qǐng)求。在登錄機(jī)制上,它將用戶(hù)名作為參數(shù)別名發(fā)送,將密碼作為scode發(fā)送。scode 參數(shù)內(nèi)的值已進(jìn)行哈希處理。分析顯示,它使用了所提供密碼值的 md5 值。請(qǐng)求中還有另一個(gè)有趣的標(biāo)志:scode 有一個(gè)屬性,其類(lèi)型值為 2。嘗試將該值賦值為1,它將接受明文密碼。成功了!因此,在明文值中使用暴力攻擊中是可能的。把它賦值給空值怎么樣?或者其他值,如-1、0或9999999999?大多數(shù)都返回了除0之外的錯(cuò)誤代碼。用屬性0做了幾次嘗試,但沒(méi)有成功,直到將密碼值作為空值發(fā)送出去。這才意識(shí)到只需提供用戶(hù)名和密碼即可訪問(wèn)任何帳戶(hù)。事實(shí)證明,這是一個(gè)很大的錯(cuò)誤。
復(fù)雜的身份驗(yàn)證機(jī)制可能成為攻擊者使用的最具隱蔽性的攻擊手段,特別是在容易出現(xiàn)業(yè)務(wù)邏輯漏洞的應(yīng)用程序上。因?yàn)樽詣?dòng)掃描器大多無(wú)法進(jìn)入這類(lèi)漏洞,所以仍然需要手工來(lái)找到它們。保障用戶(hù)的合法資產(chǎn)和權(quán)益,維護(hù)系統(tǒng)安全穩(wěn)定地運(yùn)行,身份認(rèn)證路長(zhǎng)且艱,任重而道遠(yuǎn)。