淺談身份驗證與身份授權:你是誰?你想幹嘛?
水很深,但程式開發者一定要了解的議題

前言
在開發程式的時候,我們時常會考慮要給誰使用?該限制誰使用?例如只有擁有帳號的使用者,才准許使用某些特定的服務與功能,這就是常見的登入與註冊帳號功能
這時候就會需要確認到訪你應用程式的使用者,是否符合你所期望的身份,也就是身份驗證(Authentication)程序。
然而,即便你是應用程式所認可的使用者,也未必能毫無限制地取得任何資源,或是使用任何功能。
我們可能會限制應用程式的某些部分,這些受限制的部分只會開放給特定身份的人使用,例如擁有管理者權限的人,才可以刪改特定資料等等,依照使用者身份而開放特定功能,這就是身份授權(Authorization)。
簡單來說,應用程式會問來訪使用者:「你是誰?」、「你想幹嘛?」、「我們應該允許嗎?」,就像前陣子網上流傳的,商業大佬給年輕人的三句話:「你們是誰?」「你們要幹嘛?」「你們要帶我去哪裡?」
幾乎任何規模較大的網路服務最終都需要處理以下問題: 驗證:確認你是誰? 授權:你想做什麼?我們應該允許嗎? 《FastAPI現代Python網站開發》
身份驗證
每當使用者訪問你的程式,或是來到某個你預先設定好的流程時,就會觸發這道程序。
使用者會送出的資料(例如帳號密碼)到後端資料庫做比對,符合資料庫中的其中一筆使用者資料時,你的程式就能確定這名使用者是通過驗證的「合法」使用者。
在前端網站開發中,會常見到以下兩種身份驗證機制:
Cookie-based Authentication(基於 Cookie 的身份驗證):
當使用者首次登入成功後,伺服器會建立一個「會話 (Session)」,並將這個會話的 ID 儲存在伺服器端。
同時,伺服器會向客戶端(瀏覽器)發送一個包含這個會話 ID 的 Cookie。
瀏覽器會自動儲存這個 Cookie,並在之後的每個請求中自動將其發送回伺服器。
伺服器收到請求時,會根據 Cookie 中的會話 ID 查找對應的會話資訊,從而確認使用者身份。
特性:
-
有狀態 (Stateful): 伺服器會儲存每位使用者的會話資訊,這會增加伺服器的負擔,特別是在大量使用者或需要擴展時。
-
瀏覽器自動管理: 瀏覽器會自動處理 Cookie 的發送和儲存,對開發者來說相對簡單。
-
安全性: 容易受到 CSRF (Cross-Site Request Forgery) 和 XSS (Cross-Site Scripting) 攻擊,需要額外的安全措施(如 HttpOnly 和 Secure 旗標、CSRF Token)。
-
主要用於傳統的 Web 應用程式: 特別是那些需要維護使用者會話狀態的應用程式。
Token-based Authentication(基於 Token 的身份驗證)
當使用者登入成功後,伺服器會驗證憑證(例如使用者輸入的帳號、密碼)並生成一個「Token」(通常是 JWT - JSON Web Token)。
這個 Token 會被發送給客戶端,客戶端會負責儲存這個 Token(通常在 Local Storage、Session Storage 或 Cookie 中)。
之後客戶端發送的每個請求,都需要將這個 Token 附加在請求的標頭 (Header) 中(例如 Authorization: Bearer
伺服器收到請求時,會驗證這個 Token 的有效性和簽名,如果有效,就允許訪問,而不需要在伺服器端儲存會話資訊。
前後端分離的專案常採用此種驗證策略。
特性:
-
無狀態 (Stateless): 伺服器不需要儲存會話資訊,每個請求都包含身份驗證所需的全部資訊。這使得應用程式更易於擴展和水平部署。
-
跨平台兼容: 不僅限於瀏覽器,也適用於行動應用程式和 API。
-
安全性: 如果 Token 洩露,可能會被惡意使用者利用。需要注意 Token 的安全儲存和過期機制。通常會使用 JWT,它包含簽名,防止被篡改。
-
彈性: 可以包含額外的用戶權限和角色資訊,方便授權管理。
簡單來說,Token-based Authentication是無狀態(伺服器不會記住你是誰)的驗證方式,伺服器會發給你一個憑證(token),你可以想像成一張票券,在接下來的請求裡,驗證都是認券不認人,因為伺服器不認得你(無狀態驗證)。
而Cookie-based Authentication則是會記住使用者的是誰,伺服器透過建立session並儲存,接著在回應請求的時候,為使用者進行標記(response後,瀏覽器會自動儲存伺服器發送的set cookie)。
由於每次請求,瀏覽器都會在自動攜帶cookie,所以在接下來的請求中,若遇到需要驗證時,就透過cookie內的session id,來讓伺服器比對(這個人我有標記過嗎?)。
身份授權
當你在建置應用程式服務時,你可能會先想好,哪些人可以使用你的應用程式?或者該說,哪些功能不設限?哪些功能該限制,只開放給特定使用者?
在身份驗證的程序之後,應用程式已經確認了使用者的身份,接下來就會根據使用者的身份給予特定的權限,這個權限會決定,這名使用者可以存取你的應用程式的哪些部分。
「賦予特定權限」的動作就是「授權」。
在電腦系統安全領域中,我們常會預先設定不同的角色具有不同的操作權限,這就是role-based access control (RBAC)基於角色的存取控制,白話來說,就是每一個使用者會被賦予不同的角色,每一種角色被允許可以做的事會不同,例如以下常見的情境:
- 陌生或是已註冊的一般使用者,只能瀏覽特定內容,或是創建並刪改屬於自己的內容
- 具有編輯權限的使用者則可以刪改所有使用者的內容
- 管理員則擁有所有的權限,不但可以刪改所有使用者的內容,也可以修改其他使用者的權限,甚至修改整個應用程式的規則。
可以想像一個場景,某棟嚴密管制的大樓,這棟大樓每一個樓層、房間都有電子閘門,閘門使用感應式卡片解鎖。
感應式卡片會分配給不同身份的特定人士,每個房間或樓層會有不同層級的安全鎖,因此卡片會對應不同身份的使用者,邏輯上來說,最高層級的使用者(老闆或高階主管)可以進入全部或最多的區域,反之層級越往下的就越少。
使用卡片感應電子閘門就是在同時進行身份驗證+身份授權動作,我想有使用過感應式門禁卡的人應該很容易想像。
總結來說,身份驗證確認使用者是誰?身份授權則決定這名使用者可以使用或存取應用程式的哪些部分。
驗證處理的是角色(身份),而授權處理的是內容:允許使用者存取的資源(網站端點),以及以何種方式?角色和內容的組合有很多種可能性。 《FastAPI現代Python網站開發》
小結
身份驗證與授權是個水相當深的議題,但卻是在程式開發路上必經的關卡,尤其現代程式的驗證授權技術繁多:生物識別、Oauth第三方驗證、兩步驟或無密碼驗證等等,而驗證與授權又會牽扯到資安議題,這讓原本開發起來就相當複雜的功能,又變得更加棘手。
筆者先以本篇起個頭,帶各位初步認識身份驗證與授權,之後有機會的話,在逐步深入這個議題。