最後一天,來討論一個實際應用:使用者模擬(user impersonation)功能。
下面為方便辨認,簡稱為 Impersonation。
Impersonation 就筆者所知,會用在兩個地方:
Impersonation 是一個方便,但風險極高的功能,因為如果身分驗證與權限沒控制好的話,就會造成所有人都能「模擬」任何使用者的嚴重問題了。
首先,模擬某個使用者,就類似在使用他的身分登入系統。三種身分驗證再看一次:
帳號密碼驗證是不可能的,因為被模擬的使用者才不會給密碼;第三方身分驗證也是,因為第三方也只認使用者,而不會認想模擬使用者的服務。因此較適合的選擇是 API 身分驗證。可是我們現在是要模擬使用者,而不是呼叫 API 耶?若把 API 改成「存取資源」的話,存取資源身分驗證的說法就合理許多。
以下繼續使用 API 身分驗證作為說明。
而 API 身分驗證又分成兩種,一種是 Server 互信機制,另一種是使用者授權。上述兩個情境都無法應用在使用者授權,因為使用者無法「直接地」參與瀏覽器的授權流程。因此最後就是使用 Server 互信機制。
以現有規範來說,OAuth2 的 Client Credentials Grant 是很適合作為 Server 互信機制的規範。
再看一次 Client Credentials Grant 的時序圖。
兩個情境中,第二個情境通常是需要使用者授權的,因為會有個資,而剛有提到使用者雖然無法「直接地」參與,但能「間接地」透過其他途徑授權,如電話通知。相對第一個情境一般來說則不需要,只是權限的控管就必須最小化。
以這兩個情境來說,可以定義兩種 Scope:
在 Client 得先做好註冊 client id 與 scope。而在跟授權伺服器請求授權前,身分驗證與上述的授權得先完成,才能開始請求授權。
授權完會取得 token,這個 token 可以是一個亂數,也可以是一個 JWT。若使用一般的亂數,則必須搭配 Introspection(檢查 token)來確保 token 是否還有效,以及取得 token 更多的 metadata。
相對的 JWT 的資訊都放在 token 裡了,但額外衍生的問題是:JWT 如果都是使用自我驗證來確保 token 有效,那就會無法做 Revocation(撤銷 token)。
在撤銷 token 的時候,會有三種情境:
第一種沒什麼太大問題。第二個是類似使用者想要登出,這也沒問題,因為 token 在使用者手上,登出的時候順便把 token 移除即可。
但第三種,授權伺服器想撤銷 token 的當下,資源伺服器必須要對授權伺服器做檢查才會知道這個訊息與回絕請求。若是沒有做的話,擁有 token 的服務還是能繼續跟資源伺服器請求資源。這問題在 JWT 又更為明顯--因為 JWT 可以自我驗證,不需依賴授權伺服器。
若是有做檢查機制,則如何設制控制檢查的頻率是需要思考的,每次都檢查會讓授權伺服器忙翻,隔太久又可能會出現一小段時間明明失效,但卻還有權限的怪事。另一個思考方向是,若是重要的功能就需要再次檢查 token 是否有效,比方說改密碼,或是轉帳等。
但若是使用 JWT 的話,就會比較麻煩,最好還是要在授權伺服器實作檢查機制比較恰當。
OpenID Connect 的 ID Token,也有類似的問題,因此 OpenID 有提出三個規格來實作清除 JWT 的方法:
都還是 draft,實際使用請再多加考慮
最後,來思考一下 token 有效期限。
通常 token 有效期限,會跟服務性質有關係,如台灣的網路銀行登入後的保持登入狀態只有 5 分鐘,而 Facebook 則是很長,以年來算的時間。
在情境一,假定權限預設都有好好被限制,則有效期限就不是那麼重要,跟一般登入一樣長也行;但情境二屬於特權操作,因此會建議越短越好。
最後兩天居然重感冒了,因此文章品質就不如自己預期。期望本系列文章,能讓大家對 Web 身分驗證有不一樣的認識。