這件事你大概做過上千次了。你走到校門口,掏出你的 NFC 學生證,在讀卡器上「嗶」一下,綠燈亮,門鎖「咔嗒」一聲彈開,你走進校園。
感覺是一瞬間的事。但就在這一秒鐘裡,學校其實回答了兩個問題:
- 這是一張真的卡嗎?(學校真的發過這張卡嗎?)
- 這張卡是你的嗎?(學校是不是把這張特定的卡發給了你這一個特定的學生?)
兩個答案都是「是」,門才開。任何一個是「否」,門都不會開——而且很可能會有老師走過來問你怎麼回事。
就這樣。這就是**身分驗證(authentication)**背後全部的想法——學校在確認你就是你。
本文剩下的大部分內容,也都跟「確認」有關。但問題在變,答案在變,所用的比喻也跟著變。讀完之後,你會知道 AuthN、AuthZ、MFA、OAuth、OIDC 到底是什麼意思——哪怕這些詞聽起來像是機器人打了個噴嚏。
我們從校門開始。
身分驗證(AuthN):你是誰?
當你在校門口的讀卡器上「嗶」一下你的 NFC 卡時,學校只做了一件事:確認你的身分。這件事的技術名詞叫身分驗證(authentication),通常縮寫成 AuthN。
系統會問兩個問題:
- 這張卡是真的嗎?(卡裡有一個序號,已經登記在學校的資料庫裡。)
- 這張卡是你的嗎?(你的照片、姓名、學號都存在學校的伺服器上。)
兩個答案都是「是」,門才「咔嗒」一聲打開。任何一個是「否」,門就不動。
AuthN 只回答一個問題:你是誰?
整個過程只用一秒鐘。但知道「你是誰」,並不等於學校知道你「可以做什麼」。那是下一個問題。
授權(AuthZ):你被允許做什麼?
進了校門之後,你的 NFC 卡還在工作——但是另一種工作。你走過的每一扇門都有讀卡器,每一個讀卡器都會問同一個問題:“這個學生被允許進這扇門嗎?”
這件事的技術名詞叫授權(authorization),通常縮寫成 AuthZ。
在校園裡是這樣運作的:
- 圖書館門——任何學生都能開。你一刷,它一響,你就進去。
- 教師休息室——對學生是鎖著的。只有教職員的卡能開。
- 體育館——任何學生都能進,但訪客不行。
卡知道你是誰(這是校門口那次 AuthN 給出的答案)——但卡也知道你是哪種學生。七年級的學生可以開圖書館的門。老師可以開教師休息室的門。訪客哪扇都開不了。
AuthN 與 AuthZ 的區別
AuthN 在校門口發生一次。AuthZ 在每一扇門前都發生。 你只需要證明一次「你是誰」,但你每次刷卡,系統都要再檢查一次「你能做什麼」。
最讓人困惑的是這一條:你通過了身分驗證,並不等於你被授權了。
你是一名真的學生,你的卡也是真的,校門放你進來了(AuthN ✔)。你走到教師休息室門前刷了一下,門還是鎖著(AuthZ ✘)。系統知道你是 Neo,只是覺得你不應該進去。
這就是 AuthN 和 AuthZ 一起工作的樣子。它們問的不是同一個問題——甚至連接近都談不上。
多因素認證(MFA):你真的是你嗎?
圖書館的門不太在意是誰在刷卡——幾乎任何學生都能開。但校園裡有些門不一樣。伺服器機房——那裡面存著每一個學生的成績和檔案——那扇門不會只信一次 NFC 刷卡。
要開這扇高安全等級的門,你需要兩樣東西,而不是一樣:
- 你擁有的東西——你的 NFC 卡(跟校門口用的同一張)。
- 你知道的東西——學校在開學時發給你的一個六位 PIN 碼。
你刷一下卡,讀卡器要你輸入 PIN 碼,你把它敲進去,門開了。
這件事的技術名詞叫多因素認證(multi-factor authentication),通常縮寫成 MFA。「多」的意思是不止一個因素;「因素」的意思是三類證據中的其中一類。
一共有三類證據,叫因素類別(factor class):
| 因素類別 | 它是什麼 | 校園裡的例子 |
|---|---|---|
| 你擁有的東西 | 一個實物 | 你的 NFC 卡 |
| 你知道的東西 | 你腦袋裡一個秘密 | 你的六位 PIN 碼 |
| 你本身的東西 | 你身體的一部分 | 你的指紋(高安全等級的門那裡掃描) |
單因素檢查只用其中一種。校門口只用一種——你的 NFC 卡(你擁有的東西)。高安全等級的門用兩種——你的卡(擁有)+ 你的 PIN(知道)。
MFA 的規則
攻擊者必須破解兩個不同類別的因素——而不是同一類的兩個。偷兩張卡沒用(攻擊者還是需要 PIN)。卡 + PIN 才可行。
在校門口,一個因素(卡)就夠了——學校只想知道你是真的學生。在高安全等級的門那裡,要兩個因素——因為門裡面的東西(你的成績、你的檔案)更有價值。
OAuth 2.0:安全地把權限借出去
到目前為止,所有事情都發生在校園內部。但是,如果校園外面的一個系統需要代替你做事呢?
比方說,學校有一款食堂 App。你把它裝到手機上,想用它來買午飯。這個 App 需要知道你是誰,才能從你的校園帳戶上扣錢——但你又不想把校園密碼告訴這個 App。(那組密碼你在所有地方都用;如果食堂 App 被黑了,攻擊者就能登入你的成績系統、考勤系統、信箱。)
這正好是 OAuth 2.0 解決的問題。
OAuth 2.0 是一份協定——一組規則——用來做委託授權(delegated authorization)。學校不會把校園密碼交給食堂 App。相反,學校給食堂 App 一張臨時通行證。我們把這張通行證叫做存取權杖(access token)。
過程是這樣的:
- 你在食堂 App 上刷一下你的卡(或者點「用校園帳號登入」)。
- 學校問:“你願意把這張通行證發給食堂 App,讓它能買飯嗎?”
- 你說「好」。
- 學校發出一張臨時通行證——存取權杖——給食堂 App。
- 通行證上寫著:“這個學生可以買飯。”
- 通行證一個小時後失效。
食堂 App 每次幫你買飯都用這張通行證。它永遠看不到你的校園密碼。如果 App 被黑了,攻擊者拿到的也只是這張臨時通行證——而且通行證很快就會過期。
這齣戲裡有三個角色:
- 你,這個學生——技術名詞叫資源擁有者(resource owner)(你擁有你自己的資料和你自己的權限)。
- 學校——技術名詞叫授權伺服器(authorization server)(發行證的那個系統)。
- 食堂 App——技術名詞叫用戶端(client)(拿到通行證並使用它的系統)。
OAuth 不是身分驗證協定
OAuth 是用來做授權(AuthZ)的,不是身分驗證(AuthN)。 當一個教學說「用 Google 登入」時,它其實說的是 OpenID Connect——也就是 OAuth 加上一個身分層。單純的 OAuth 不會讓你「登入」——它只是給另一個系統發一張通行證。
三個角色的連結關係是這樣:
這張圖從上往下讀。學生在最上面,在校門口的讀卡器上刷一下卡。學校給食堂 App 發兩張權杖:存取權杖(OAuth)和——在使用 OIDC 時——一個 ID 權杖(下一節)。食堂 App 用這兩張權杖代替學生買飯。學生從來不會交出密碼。
OpenID Connect(OIDC):在通行證上加進「你是誰」
OAuth 給食堂 App 一張臨時通行證——但通行證上只寫著*“這個學生可以買飯”。它沒說是哪一個學生*。這是個問題:食堂需要知道該誰的校園帳戶上扣錢。
OpenID Connect(OIDC) 解決了這個問題。OIDC 是 OAuth 加上身分。學校在發出臨時通行證的同時,還會再發第二張權杖——ID 權杖(ID token)——裡面裝著這個學生被核驗過的身分資訊:
- 學號
- 照片
- 全名
- 班級 / 年級
ID 權杖由學校簽章(這樣食堂 App 才能驗證它是真貨),它會告訴食堂 App 到底誰在買飯。
所以現在有兩張獨立的權杖:
- 存取權杖——臨時通行證(OAuth)。說你能做什麼。
- ID 權杖——被核驗過的身分(OIDC)。說你是誰。
兩張權杖通常都是 JWT(JSON Web Token)的格式,也就是「帶簽章的 JSON 物件」。但它們承擔不同的職責。如果你想深入了解,可以去看 OpenID Connect Core 1.0 規範——裡面有權杖格式、支援的所有流程、以及加密簽章的具體規則。
JWT 的 scope:貼在通行證上的標籤
到這裡,你已經好幾次聽到「權杖(token)」這個詞了。權杖就是學校發出來的一小段資料——一張臨時通行證,上面寫著你是誰(或者你能做什麼,或者兩者都寫)。
如今最常見的權杖格式叫 JWT——JSON Web Token。JWT 是一個字串,看起來像是三段很長的隨機詞用點連起來:eyJhbGc...header.eyJzdWI...payload.SflKxw...signature。第一段是 header(用了什麼演算法),第二段是 payload(真正的資料——你的名字、你的權限,等等),第三段是 signature(一個加密印章,證明這個 JWT 沒人改過)。
JWT 能裝很多東西,但其中最重要的是一列scope(授權範圍)。scope 是通行證上的一個標籤,寫著這張通行證能做什麼。
回到食堂的例子:
"library access"——可以借書。"cafeteria purchases"——可以買飯。"gym entry"——可以用體育館。"grades:read"——可以讀成績(這就有點危險了)。
食堂 App 的權杖上只有 "cafeteria purchases"。它沒有 "grades:read"。所以當它想讀成績的時候,學校的系統會說:“這張通行證沒貼那個標籤——拒絕。”
但如果權杖到達時根本沒有任何 scope 呢?它還是一張真通行證——簽章能驗過——但它上面沒有標籤。接收方的系統不知道這張通行證是拿來開哪扇門的。
這種情況有兩種策略:
- 預設拒絕(default-deny,穩妥)——因為通行證沒有標籤,系統直接拒絕。“這張通行證沒有 scope,那我們一律拒絕。”
- 預設放行(default-allow,冒險)——系統看不出它不能做什麼,乾脆讓它什麼都能做。
沒有 scope 的 JWT 是危險的
一個表現良好的 API 會把一個沒有 scope 欄位的 JWT 當成「未授予任何 scope」——在功能上等同於拒絕。最經典的錯誤就是預設放行:食堂 App 突然能看成績、看考勤、看任何東西,因為系統分不清它不能做什麼。
這張圖畫出了決策樹。如果 JWT 沒有 scope 欄位,穩妥的選擇是拒絕(左上分支)。如果有 scope 欄位,系統就讀出 scope,然後檢查「請求的動作」是不是落在「授予的集合」裡。
五個概念,各用一段話講完
讀到這裡,你已經能回答「AuthN 和 AuthZ 有什麼區別」了。你也能跟朋友講清楚,為什麼 OAuth 不等於「登入」。
一句話回顧:
- AuthN = 在校門口的讀卡器上嗶一下你的 NFC 卡。
- AuthZ = 嗶一下之後,哪些門會打開。
- MFA = 在高安全等級的門那裡要卡 + PIN。
- OAuth = 給另一個系統(比如食堂 App)一張臨時通行證,讓它代替你做事。
- OIDC = 一張臨時通行證,再附上一張核驗過的學生證。
- JWT 裡沒有 scope = 一張沒貼標籤的通行證——老師看不懂,系統也可能出安全問題。
如果你想從這裡接著往前走,本文之外還有更多內容。想做實作的下一步——“我自己要怎麼保管密碼?“——可以去看 密碼管理器(Password Managers) 那篇。如果你喜歡這種風格,又想看更偏管理層的深度版——聊聊當身分認證在組織層面纏成一團*時會怎樣——可以去看 品質天花板(The Quality Ceiling)——同一個比喻的味道,不同的尺度。
References
- RFC 6749 — The OAuth 2.0 Authorization Framework (IETF). https://datatracker.ietf.org/doc/html/rfc6749
- OpenID Connect Core 1.0 specification. https://openid.net/specs/openid-connect-core-1_0.html
- RFC 7519 — JSON Web Token (JWT) (IETF). https://datatracker.ietf.org/doc/html/rfc7519
- NIST SP 800-63B — Digital Identity Guidelines: Authentication and Lifecycle Management. https://pages.nist.gov/800-63-3/sp800-63b.html
留言
請接受「功能性」Cookie 類別以查看和發表留言。
留言載入失敗。您可以重試,或前往 GitHub 查看討論。
在 GitHub 上查看