隨手扎
【用Keycloak學習身份驗證與授權10】深入OAuth 2
喔不,其實今天還不會真正提到OAuth 2.0的深度內容。今天要來談談的是取得資源的細節。
使用帳號密碼,假裝自己是用戶
首先先試著想想看,如果你想要寫一支程式代替你處理某些事情。譬如:收信、發信。 更詳細的說,你寫了一個信件的客戶端(如:Thunderbird、Outlook)。 然後你會需要告訴這支程式你信箱的登入帳號密碼,由他去代替你收信、寄信。這個樣子就像是你把你所有的祕密都交給了它, 交給了它那把萬能鑰匙,而你完全信任這支程式。
其實這種狀況還真不少見。尤其在於你所申請的帳號,和使用的客戶端服務實際就是同一個時,這種行爲在正常不過。
但當它們是不同服務時,就可能出現問題了。你還能信任你提交的密碼不會被誤用嗎?不可能發生?
你可能有Gmail的帳號,你會很正常的使用Gmail的服務。但你知道Gmail除了自己本身外,它還可以幫你收其他信箱嗎?
比如說你還有ymail的帳號,但你更喜歡Gmail的界面,所以你希望使用Gmail來處理yamil的信件。這時候其實你就是告訴了Gmail 關於yamil的帳號密碼。相對的,也就是你應該是信任的Google的服務。
當在使用的服務是同一個提供商時,這種直接使用帳號密碼的情況就相當正常。他們本就可以共用一些資訊,可能使用了相同的記憶體空間、 使用了相同的資料庫等。
actor "用戶" as user
rectangle 共同的服務提供商 {
usecase "建立帳號" as create_account
usecase "使用信箱服務" as use_mail
rectangle 資料庫 as database {
}
}
user --> create_account
user --> use_mail
create_account --> database
use_mail --> database
但或許你該留意使用的真的是同一個服務,還是其實是一個代理(Proxy)?
actor "用戶" as user
rectangle 其他服務 as other {
}
rectangle 共同的服務提供商 as service {
usecase "建立帳號" as create_account
usecase "使用信箱服務" as use_mail
rectangle 資料庫 as database {
}
}
user --> create_account
user --> other
other --> use_mail
create_account --> database
use_mail --> database
當使用代理時,這樣的情況,這個代理有可能短暫的持有你的帳號密碼資訊。
特殊密碼
我們將這個代理,再擴展一些。它或許不只是一般的軟體,更是作業系統,乃至硬體。
想想,你一般使用私人電腦收信。但偶爾,你會需要使用公司電腦、公共電腦登入。儘管或許你還是使用Gmail的服務, 但實際上這之中通過了好幾層代理。
首先,硬體、作業系統上你不知道有沒有安裝硬體鍵盤記錄器。接著瀏覽器也同樣是一個代理,使用的是可信任的瀏覽器嗎?
那該怎麼辦?我們可以與服務約定一種「特殊密碼」。這種密碼只能使用一次,是一次性密碼(OTP, One Time Password)。 現在一次性密碼更常見到於二階段驗證(雙因子驗證/2FA, Two Factor Authentication)。但實際上存在非常多種形式:
- 透過簡訊驗證: 透過簡訊寄送一組限時且只能使用一次的密碼
- 透過信箱驗證: 透過信箱寄送一組限時且只能使用一次的密碼
- 特殊連接驗證: 透過一個特殊的連接,該連接有時效性,且只能存取一次。
- 透過時間產生特殊密碼: TOTP, Time-base One Time Password。
- 透過雜湊產生特殊密碼: HOTP, HMAC-based One Time Password。
- 與系統服務約定好數組一次性密碼
- 與系統服務約定好特殊狀況使用密碼
- 使用行動裝置登入
當然可能遠不止這些,其中簡訊、信箱寄送驗證密碼或許有相當多人用過。所以也就挑幾個來說說:
第3個,如果你有使用過Medium、Notion 、Tumblr 的話,他們都可以透過信箱寄送一個 神奇的連接 讓你登入。
第6個,實際你在使用Android的話,Google有儲存幾組動態的在你的手機,雖然這可能更像是第4、5個。(iPhone好像也有,有段時間Facebook也可產生)
第7個,同樣可以申請一組在特定情況使用的密碼。像是Facebook可以申請應用程式密碼。當在使用非Facebook的應用程式,但需要使用Facebook登入時, 不必輸入Facebook的密碼,只要輸入這個特殊密碼即可。
開發者權杖
還有一種情況是,你本身在開發的應用本就是系統服務框架下的一部分,你本身就是開系統的開發人員之一。你已可能有一把非常強大的開發者鑰匙(密碼或權杖)。 你或許會去驗證使用者身份或許不會,但你直接使用這個鑰匙來處理服務。
爲什麼會有這種情況?或許該子服務本身就設計成只有開發者權杖,細部控制並不夠精細,所以需要一個看門人(gatekeeper)來檢查是否有權限操作服務。
委託授權
以上,雖然有一點授權的味道了,但是都是 整份授權 。都還沒有把權限拆分更小的部分分開授權,相對的更接近驗證的部分。
委託概念是 OAuth 強大功能的根基。雖然 OAuth 經常被稱作授權協議(這是RFC中給出的名稱),但它也是一個委託協議。 通常,被委託的是用戶全向的子集,但是 OAuth 本身並不承認或傳遞權限。相反,它提供了一種方法,讓客戶端可以請求用戶將部分權限委託給自己。然後,讓用戶可以批准這個請求。批准之後,客戶端就可以去執行這些操作了。
– OAuth 2.0實戰
還記得在「什麼是OAuth」說過: OAuth沒有定義權杖格式 。 所以它可以很像是上面提到的特殊密碼,不同的是現在不將整份權限授權出去,而只授權一部分。
在我們「快速開始」有這麼一個操作畫面:
我們只授權了該應用存取角色、Email資訊和帳號資訊,並且最後會產生一組特殊密碼。
但由於OAuth委託過程需要資源擁有者參予。需要擁有者確認授權這件事情或許不是每種情況都可以做,所以你可以將其設計爲白名單、灰名單和黑名單。
- 白名單: 不需要用戶的明確授權。 適用於內部可信任的機構或團體。
- 灰名單: 採用用戶首次使用時確認。 由用戶決定是否加入白名單或黑名單。
- 黑名單: 由集中控制機構,決定是否放行應用。
此外你會注意到,在之後登入「快速開始」應用時,並沒有在要求授權一次。 這是基於 首次使用時信任原則(TOFU, Trust On First Use) 。
你可以透過 http://localhost:8080/auth/realms/quick-start/account/#/applications 來查看已經授權的應用,同樣也可以用來撤銷授權。
參考資料
- OAuth 2.0實戰
- Gmail說明 - 透過不同的地址或別名傳送電子郵件
- 維基百科 - 多重要素驗證
- wikipedia - HOTP
- wikipedia - TOTP
- 如何使用應用程式密碼
- 使用應用程式密碼登入帳戶
