網站怎麼知道你是你
你每天都在登入:信箱、網購、記帳 App。輸入一次密碼,接下來點來點去,網站好像都記得你。
這一課要回答一個看起來很簡單的問題:網站到底是怎麼記得你的?
大約 5 分鐘,不需要任何程式基礎。
伺服器是個健忘的櫃檯
想像網站背後有一位櫃檯人員,專門處理你的每一個要求:看帳本、記一筆支出、改設定。
但這位櫃檯有個怪毛病:每件事一處理完,就立刻忘記你是誰。你上一秒才跟他講過話,下一秒他就不認得你了。
真實世界
網站的伺服器真的是這樣運作的。你每點一下,瀏覽器就送出一個獨立的請求request,伺服器處理完就結束,不會自動記得上一個請求是誰送來的。
這種特性叫做無狀態stateless。
為什麼要設計得這麼健忘?因為伺服器同時要服務成千上萬人。如果要一直記著每個人,很快就會塞爆。健忘,反而讓它能服務更多人。
試試看:健忘的櫃檯
先按「登入」,再試著看你的帳本或記一筆帳。
發現了嗎?明明剛剛才登入成功,櫃檯馬上就不認得你了。
那每次都報上帳號密碼呢?
最直覺的解法:每做一件事,都把帳號密碼再講一次。這樣櫃檯就一定知道你是誰。
可以是可以,但有兩個問題。
密碼到處跑很危險。每點一下,密碼就被送出去一次。送得越多次,被偷看的機會就越大。
每次都核對密碼很慢。核對密碼這件事,是刻意設計得很費工的,這樣壞人才沒辦法一秒猜幾百萬次。如果每點一下都核對一次,網站就會變得很卡。
我們需要更好的辦法。
登入一次,換一個證明
去遊樂園的時候,你只在門口買一次票。買完票,工作人員給你一個手環。之後玩每一個設施,亮一下手環就好,不用每次都掏錢包。
網站也是這樣:
這個「證明」,就是整套課程的主角。
再試一次,這次有手環
一樣先登入,再看帳本、記帳。注意你每次說話時,多帶了什麼。
櫃檯還是一樣健忘,他並沒有記住你。是你每次都帶著手環,所以他每次都認得出來。
這一課學到的
網站的伺服器很健忘,每個請求處理完就忘記你是誰(無狀態)。
每次都報帳號密碼又危險又慢,所以網站的做法是:登入一次,換一個證明,之後每次都出示這個證明。
下一課會看到,這個「證明」其實有兩種完全不同的做法。
兩種記住你的方法
上一課說到,登入之後網站會給你一個「證明」,之後每次都出示它。
這個證明有兩種常見的做法。好消息是,兩種你在生活中都用過。
做法一:寄物櫃號碼牌
去博物館寄放包包,櫃檯給你一張號碼牌。
A27
號碼牌上只有一個號碼,沒有其他資訊。你的包包放在櫃檯後面。要取回的時候,櫃檯拿著號碼,走到後面去找。
真實世界
這種做法叫做session工作階段。你登入後,伺服器在自己的資料庫記下「A27 是 小明」,只把號碼交給你的瀏覽器保管。之後你出示 A27,伺服器就去查表。
做法二:隨身通行證
參加研討會時,你拿到的名牌上直接印好了:
通行證
- 姓名
- 小明
- 身分
- 一般會員
- 有效到
- 今天 18:00
工作人員看一眼名牌,就知道你是誰、能不能進,不用回報到處查名單。
真實世界
這種做法叫做token權杖、令牌。資料直接寫在你帶著的東西上,伺服器看了就知道,不用查表。
最常見的 token 格式叫 JWT,第二單元會把它整個拆開來看。
比一比:櫃檯要忙多久
分別按下兩邊的按鈕,看櫃檯要做幾件事。
這裡的秒數是故意放慢的。真實世界的差距只有幾毫秒,但一天幾百萬次請求,累積起來就很可觀。
等等,通行證不能自己改嗎?
通行證看起來又快又方便。但資料既然寫在你手上……你自己改一下會怎樣?
試著把「身分」改掉,再拿去給櫃檯看。
通行證
- 姓名
- 小明
-
- 有效到
- 今天 18:00
這顯然不行。如果通行證上的字誰都能改,那它根本沒有用。
號碼牌就沒有這個問題,因為真正的資料在櫃檯後面,你改不到。通行證要怎麼防止被亂改?答案在第三單元:給它蓋上一個改不了的章。
兩種做法,各有好壞
兩種都是正當的做法,很多網站甚至兩種一起用。
這套課要學的 JWKS,是一套讓「通行證」做法變得安全又好用的方法。
這一課學到的
證明有兩種做法:號碼牌(session)只給你一個號碼,資料留在伺服器;通行證(token)把資料直接寫在你身上,伺服器不用查表。
通行證比較快,但有個大問題:內容如果能被亂改,就一點用都沒有。
下一課會看到,當服務越變越多,通行證的好處會變得更明顯。
一間總部、很多分店
到目前為止,我們都假設網站只有一個櫃檯。但真實的服務,常常不只一個。
這一課會看到,服務一變多,「證明」的做法就會變得很關鍵。
服務變多了
假設你做了一套服務:記帳、相簿、行事曆。每一個都是獨立的小網站,但你希望使用者只要登入一次,三個都能用。
這時候,負責登入的那一個就像總部,其他的就像分店。使用者在總部登入,然後到各間分店使用服務。
真實世界
這是很常見的架構:一個專門負責登入的驗證服務auth server,加上很多個各自獨立的下游服務downstream services。
做法 A:分店每次都打電話問總部
如果用號碼牌的做法,問題來了:你在總部拿到號碼牌,但號碼對應的資料存在總部,分店自己查不到。
所以客人每次到分店出示號碼牌,分店都只好打電話回總部問:「A27 是誰?」
分店少的時候還好。分店一多,總部的電話就響個不停。更慘的是,總部只要一停電,所有分店都沒辦法做生意。
做法 B:分店自己看通行證
如果改用通行證,資料就寫在通行證上。分店看一眼就知道你是誰,完全不用打電話。
總部只有在你登入的那一刻忙一下,發完通行證之後就輕鬆了。
下一步,我們實際比較兩種做法。
試試看:總部撐得住嗎?
先選做法 A,把分店數量拉高,再按「總部停電」。然後換成做法 B,再試一次。
假設每間分店每分鐘有 60 位客人。做法 B 停電時,已經拿到通行證的人照樣能用;只有還沒登入的新客人,要等總部恢復。
新問題:分店怎麼知道通行證是真的?
做法 B 看起來很完美。但還記得上一課的問題嗎?通行證上的字如果能被亂改,分店看了也是白看。
更麻煩的是,分店也不能打電話問總部「這張是真的嗎?」,不然又回到做法 A 了。
所以我們需要的是:
一種讓分店自己就能檢查真假的方法,而且完全不用聯絡總部。
這就是 JWKS 要解決的問題,也是接下來整套課的目標。
認識故事裡的角色
接下來的課程,都會用這個故事來講。右邊的名字現在看不懂沒關係,左邊那欄你已經都懂了。
先偷偷預告答案:總部在每張通行證上蓋自己的印章,分店則拿印鑑證明來比對。印章只有總部有,所以沒人偽造得了;印鑑證明誰都能看,所以分店不用打電話也能檢查。
這一課學到的
服務一多,就會變成「一間總部、很多分店」。如果分店每次都打電話問總部,總部會很忙,而且一停電大家都完蛋。
改用通行證,分店就能自己判斷。但前提是:分店必須能自己確認通行證沒被偽造。
第一單元到這裡結束。第二單元,我們要把一張真的通行證拆開來看。
看起來像亂碼的通行證
第一單元一直在講「通行證」。這一課,我們終於要看一張真的。
先打個預防針:它長得非常嚇人。但看完這一課,你會發現它其實很好懂。
大約 5 分鐘,不需要任何程式基礎。
這就是一張真的通行證
下面這一長串,就是總部發給 小明 的通行證,也就是你的。每次你在分店做事,瀏覽器都會偷偷把它附上去。
eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiLlsI_mmI4iLCJhdWQiOiJsZWRnZXIiLCJyb2xlIjoibWVtYmVyIiwiaWF0IjoxNzkxODU2ODAwLCJleHAiOjE3OTE4NTc3MDB9.AtYMpoawQJ0ax16ASnQ5UX5tGRS00klMRHex1-efRUzvDE2eSXX3uZnAnbFnr7xP6UsvLOi6XytkxASBbWPTyw
看起來像貓咪踩過鍵盤,對吧?沒關係,先別試著讀懂它,下一步我們找一個小線索。
真實世界
這種格式叫做 JWTJSON Web Token,很多人唸成「jot」。幾乎所有用通行證做法的網站,用的都是它。
線索:裡面藏了兩個點
仔細看,這一長串裡面有兩個小小的「.」。很難找,我們請機器幫忙。
eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiLlsI_mmI4iLCJhdWQiOiJsZWRnZXIiLCJyb2xlIjoibWVtYmVyIiwiaWF0IjoxNzkxODU2ODAwLCJleHAiOjE3OTE4NTc3MDB9.AtYMpoawQJ0ax16ASnQ5UX5tGRS00klMRHex1-efRUzvDE2eSXX3uZnAnbFnr7xP6UsvLOi6XytkxASBbWPTyw
兩個點,切成三段
兩個點把通行證切成三段,每一段負責不同的事。就像一張紙本通行證,有抬頭、內容、印章三個區塊。
eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiLlsI_mmI4iLCJhdWQiOiJsZWRnZXIiLCJyb2xlIjoibWVtYmVyIiwiaWF0IjoxNzkxODU2ODAwLCJleHAiOjE3OTE4NTc3MDB9.AtYMpoawQJ0ax16ASnQ5UX5tGRS00klMRHex1-efRUzvDE2eSXX3uZnAnbFnr7xP6UsvLOi6XytkxASBbWPTyw
第一段:抬頭。說明這張通行證用什麼方式蓋章、蓋的是哪一顆章。
第二段:內容。你是誰、什麼時候到期,這些資料都在這裡。
第三段:印章。用來證明這張通行證是總部發的、沒被改過。
真實世界
三段的正式名稱分別是 header標頭、payload內容、signature簽章。
為什麼要長得這麼亂?
寄包裹時,郵局只收標準尺寸的紙箱。你的東西形狀再奇怪,都要先裝進標準紙箱才能寄。
通行證也一樣。它要放在網址、或網路請求的「標頭」裡面一起傳送,那些地方只接受一些安全的英文字母和數字。所以總部會先把內容轉換成這些安全字元,才發給你。
這就是它看起來像亂碼的原因:不是故意藏起來,只是換了一種包裝。
這種轉換方式叫做 base64,下一課會親手試試看。
小測驗
如果你想知道這張通行證是發給誰的,應該看哪一段?
這一課學到的
真正的通行證叫 JWT,看起來是一長串亂碼,其實被兩個點切成三段:抬頭、內容、印章。
它看起來亂,是因為內容被轉換成安全字元方便傳送,不是因為被藏起來。
下一課,我們要親手把它「轉回來」。
base64 不是加密
上一課說,通行證被「轉換」成一長串英文字母和數字。
很多人看到這種亂碼,第一個反應是:「喔,這是加密過的,很安全。」這一課要告訴你:完全不是這樣。
base64 是一張公開的對照表
還記得摩斯密碼嗎?「・-」代表 A,「-・・・」代表 B。看起來很神秘,但對照表到處都查得到,誰都能翻回來。
base64 也是一張對照表。它把任何資料,換成 64 個「安全字元」來表示:大寫 A 到 Z、小寫 a 到 z、數字 0 到 9,再加兩個符號。
真實世界
通行證用的是稍微改良過的 base64url:把容易在網址裡出問題的「+」和「/」換成「-」和「_」,並拿掉結尾的「=」。原理完全一樣。
試試看:轉換機
在上面打任何字,中文也可以,下面會立刻變成 base64url。
注意到了嗎?轉過去、轉回來,都不需要任何密碼。
那加密是什麼?
加密比較像把東西鎖進保險箱。沒有鑰匙,就算箱子擺在你面前,你也打不開。
看起來看不懂,跟別人真的解不開,是兩回事。
挑戰:破解這一段
這是從某張通行證裡剪下來的一段:
所以,通行證裡不能放什麼?
既然誰拿到通行證都能看光第二段的內容,總部就不能在裡面放秘密,例如:
密碼、身分證字號、信用卡號、病歷,或任何你不想讓別人看到的東西。
真實世界
JWT 的內容預設是誰都能讀的。它保護的是「不能被偷改」,不是「不能被偷看」。怎麼做到不能被偷改,就是第三段印章的工作。
這一課學到的
base64 只是一張公開的對照表,把資料換成安全字元方便傳送,誰都能轉回來。
它不是加密,所以通行證的內容誰都看得到,裡面不能放秘密。
下一課,我們用轉換機把那張真的通行證整個拆開。
拆開通行證
現在你知道 base64 只是換包裝了。這一課,我們把第 4 課那張通行證的前兩段拆開來看。
eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiLlsI_mmI4iLCJhdWQiOiJsZWRnZXIiLCJyb2xlIjoibWVtYmVyIiwiaWF0IjoxNzkxODU2ODAwLCJleHAiOjE3OTE4NTc3MDB9.AtYMpoawQJ0ax16ASnQ5UX5tGRS00klMRHex1-efRUzvDE2eSXX3uZnAnbFnr7xP6UsvLOi6XytkxASBbWPTyw
拆開第一段:抬頭
把粉紅色的第一段丟進轉換機,會得到這個。點一行看看它是什麼意思:
{
}
(點上面任何一行)
真實世界
這種用大括號和引號寫資料的格式叫做 JSON。每一行都是「名稱:值」的組合。
拆開第二段:內容
黃色的第二段解開後,就是通行證上的所有資料。一樣點一行看看:
{
}
(點上面任何一行)
真實世界
內容裡的每一條資料,叫做一個 claim聲明。iss、sub、aud、iat、exp 都是大家約定好的名稱,所以只有三個字母,讓通行證短一點。
那串大數字是時間
電腦記時間的方式很特別:從 1970 年 1 月 1 日開始,數過了幾秒。所以 1791856800 其實是一個日期。
把滑桿拉過 15 分鐘看看。到期時間一過,同一張通行證就沒用了。
做一張你自己的通行證
既然拆得開,就也組得回去。填一填,下面會即時做出一張通行證:
前兩段你自己就做得出來。但第三段印章是空的,因為你沒有總部的印章。
這一課學到的
第一段抬頭寫著蓋章方式和用哪一顆章;第二段內容寫著誰發的、是誰的、給誰用、什麼時候到期。
時間是從 1970 年開始數的秒數。過了到期時間,通行證就失效。
你也發現了:前兩段誰都做得出來。那分店要怎麼分辨真假?答案在第三段,下一課揭曉。
那第三段呢?
前兩段,你已經會拆、也會做了。只剩下綠色的第三段:印章。
這一課要回答第 2 課留下的大問題:通行證寫在你手上,那為什麼你不能自己亂改?
把第三段丟進轉換機
前兩段解開都是看得懂的文字。第三段呢?
AtYMpoawQJ0ax16ASnQ5UX5tGRS00klMRHex1-efRUzvDE2eSXX3uZnAnbFnr7xP6UsvLOi6XytkxASBbWPTyw
試試看:偷改通行證
我們來當一次壞人。把第二段的身分改掉,再重新轉換回去:
改了之後,只有第二段變了,第三段印章還是原本那一串。這就是破綻。
印章是「對著內容」蓋的
公文上常看到「騎縫章」:印章蓋在兩張紙的接縫上,一半在這張、一半在那張。只要有人偷換其中一頁,章就對不起來了。
通行證的印章也是這樣。總部是根據前兩段的內容算出第三段的。內容一改,原本的印章就對不上了。
真實世界
第三段叫做 簽章signature。總部用一把只有它才有的鑰匙,對「第一段.第二段」這整串算出簽章。分店收到通行證時,重新檢查簽章和內容對不對得上。
試試看:對照機
我們先用一個簡化版來感受:每段內容都有一個獨一無二的「指紋」,內容差一個字,指紋就完全不同。
- 總部發證時記下的指紋
- 計算中……
- 現在這張的指紋
- 計算中……
光有指紋還不夠
你剛剛發現了:如果第三段只是「指紋」,壞人改完內容,自己重算一個新指紋就好,分店根本分不出來。
所以真正的第三段,必須是只有總部才做得出來的東西。就像總部的印章,別人沒有那顆章,就蓋不出一樣的章。
指紋是什麼、印章怎麼做到只有總部能蓋、分店又怎麼不用打電話就能檢查,就是第三單元要講的。
這一課學到的
第三段不是文字,是總部對著前兩段的內容算出來的簽章。
壞人如果偷改內容,簽章就對不上,分店就會發現。但前提是:簽章必須是只有總部才做得出來的。
第二單元到這裡結束。你已經能把一張真的通行證拆開、讀懂,也知道它怎麼防偷改了。
指紋機
第 7 課的「對照機」用到了一種叫「指紋」的東西。這一課,我們好好認識它。
它是整個第三單元的地基,後面的印章都會用到它。
果汁機的四個特性
想像一台很特別的果汁機。不管你丟什麼進去,它都會打出一杯固定大小的果汁:
一、同樣的水果,永遠打出同樣的味道。今天打、明天打,結果一模一樣。
二、差一點點,味道就完全不同。多放一顆葡萄,整杯味道都變了,不是「有一點點不一樣」。
三、打不回去。給你一杯果汁,你沒辦法把它變回原本的水果。
四、杯子大小固定。丟一顆葡萄或一整箱西瓜,都是同一杯的量。
真實世界
這種「指紋機」叫做雜湊函數hash function,最常見的一種叫 SHA-256。不管輸入多長,它都會算出一串固定 64 個字的指紋。
試試看:指紋機
打任何字,下面會即時算出它的 SHA-256 指紋。這是真的在你的瀏覽器裡算的。
試著把同一句話打兩次,指紋會一模一樣;刪掉一個空白,指紋就整個變了。
找不同:只差一個標點
這兩句話只差了最後的句號:
差一個標點,指紋卻幾乎每個字都不同。所以只要內容被偷改一點點,指紋馬上就對不上。
打不回去,只能猜
總部把一個水果的名字丟進指紋機,只告訴你指紋:
計算中……
指紋沒辦法「倒推」回原文。你唯一能做的,是把猜的答案也丟進指紋機,看指紋對不對得上:
指紋的弱點
指紋很適合用來檢查「內容有沒有被改過」。但還記得第 7 課的最後嗎?
指紋機是公開的,誰都能用。壞人改完通行證的內容,自己丟進指紋機重算一個新指紋,分店就分不出來了。
所以光有指紋不夠。我們需要一種只有總部做得出來的東西。下一課,先試試最直覺的辦法。
這一課學到的
指紋機(雜湊函數)會把任何內容變成固定長度的指紋:同樣內容同樣指紋、差一點就完全不同、而且打不回去。
它能抓到內容被偷改,但因為誰都能算,壞人也能重算一個新的。
共用一顆印章的問題
上一課說:指紋誰都能算,壞人改完內容可以重算一個。那如果加一個只有自己人知道的秘密呢?
加了秘方的指紋
總部和分店私下約好一句暗號,例如「芝麻開門」。計算指紋時,把暗號一起丟進去。
壞人不知道暗號,就算改了內容,也算不出正確的指紋。分店只要用同一句暗號重算一次,就知道是不是自己人做的。
真實世界
這種「加了秘密的指紋」叫做 HMAC。用它來蓋章的 JWT,抬頭裡的 alg 會寫 HS256。暗號就叫做共享秘密shared secret。
試試看:暗號章
總部用暗號「芝麻開門」幫你的通行證蓋了章。壞人想把身分改成管理員:
試試把暗號改成「芝麻開門」再按一次。猜中暗號,就騙得過去。
麻煩在後面:每間分店都要知道暗號
暗號章有一個大問題:分店要檢查,就得自己也知道暗號。服務越多,暗號就散落在越多地方。
就像共用一顆印章
暗號章,等於總部刻了好幾顆一模一樣的印章,每間分店發一顆。分店拿它來比對,但它同時也能蓋章。
只要其中一間分店把印章弄丟,壞人就能拿著它,在每一間分店都暢行無阻。分店越多,弄丟的機會就越大。
我們真正需要的是:一種分店拿來只能檢查、不能蓋章的東西。
這一課學到的
在指紋裡加一句只有自己人知道的暗號(HMAC),壞人就算不出正確的章。
但每間分店都要知道暗號才能檢查,等於大家共用一顆印章:一間被駭,全部淪陷。
下一課,終於要介紹解決這個問題的主角:印章和印鑑證明。
偷改通行證
第 2 課的問題,終於可以完整回答了:通行證寫在你手上,你能不能自己改?
這一課,總部已經用真的印章幫 小明 蓋好了一張通行證。你要當壞人,用盡辦法騙過分店。
總部發的通行證
分店手上只有總部的公鑰。接下來每一招,都會交給分店用公鑰比對。
第一招:只改內容
把身分改成管理員,重新轉換第二段,章不動:
第二招:自己刻一顆章
既然章對不上,壞人乾脆自己做一對金鑰,用自己的印章重新蓋:
第三招:剪貼別人的章
總部幫另一個人(管理員)也蓋過通行證。壞人把那張的章剪下來,貼到自己改過的內容上:
唯一騙得過的方法
三招都失敗了。唯一能讓分店點頭的,是用總部的私鑰蓋章。
所以整套系統的安全,最後都落在一件事上:總部的私鑰要藏好。公鑰則可以大方地發給所有分店。
真實世界
總部發證時用私鑰對「第一段.第二段」簽章;分店收到後用公鑰驗證簽章。這個流程叫做數位簽章digital signature,JWT 的第三段就是它。
這一課學到的
只改內容、自己刻章、剪貼別人的章,全部都會被公鑰抓包。只有總部的私鑰蓋得出分店認得的章。
第三單元到這裡結束。最後一塊拼圖是:分店要去哪裡拿總部的公鑰?公鑰換了怎麼辦?這就是第四單元的「公告欄」:JWKS。
印章編號與換印章
印章用久了要換:可能是定期更換,也可能是懷疑被偷看過。
但總部已經發出去好多張通行證了。換了章之後,那些舊通行證怎麼辦?
公告欄可以同時貼好幾張
每一顆印章都有編號(kid),通行證的抬頭會寫著「我是用幾號章蓋的」。
公告欄上可以同時貼好幾張印鑑證明。分店看通行證上的編號,挑對應的那一張來比對。新舊印章就能同時存在。
試試看:換印章的四個步驟
依序按下每個步驟,看公告欄、舊通行證和新通行證會怎樣:
順序很重要
如果總部先改用新章、才貼公告,會發生什麼事?
所以正確的順序是:先貼新的印鑑證明,等大家都抄到了,才開始用新章;等舊通行證都過期了,才撤下舊的。
遇到沒見過的編號
分店收到一張通行證,上面的印章編號在自己抄的公告上找不到。合理的做法是:回公告欄重新抄一次,還是找不到才拒絕。
真實世界
換印章叫做金鑰輪替key rotation。好用的驗證工具都會內建「遇到不認識的 kid 就重抓 JWKS」,所以只要總部照順序換,分店完全不用改程式。
這一課學到的
通行證抬頭的 kid 告訴分店該用哪一張印鑑證明。公告欄可以同時貼新舊兩張,所以換印章時舊通行證不會突然失效。
換章的順序:先貼新的 → 再改用新章 → 舊通行證都過期後撤下舊的。
收不回來的通行證
有人離職了、帳號被盜了,總部想讓他的通行證立刻失效。
這是通行證做法最大的弱點。這一課要誠實地面對它。
分店不問總部,就不知道
通行證的好處,是分店自己就能檢查、不用打電話問總部。
但反過來說,總部在後台把某人停權了,分店根本不會知道。只要通行證的章是真的、也還沒過期,分店就會放行。
通行證發出去,就像潑出去的水,收不回來,只能等它自己過期。
試試看:有效期限要多長?
拉一拉通行證的有效期限,看看停權之後,壞人還能用多久:
常見的解法:短效通行證+續約
總部發兩樣東西給你:一張很快就過期的通行證(例如 15 分鐘),和一張續約卡。
通行證過期時,瀏覽器會自動拿續約卡回總部換一張新的。總部在這個時候檢查:如果你被停權了,就不給換。
真實世界
短效的通行證叫 access token,續約卡叫 refresh token。續約卡只會拿去總部用,分店看不到它。
真的很重要的事,另外問總部
轉帳、刪除帳號、修改密碼這種事,晚 15 分鐘停權都太久。
所以很多網站會在這些高風險的動作前,另外打一通電話回總部確認一次。大部分的請求照樣快速放行,只有關鍵的那幾個多花一點時間。
這一課學到的
通行證發出去就收不回來,分店不會知道有人被停權。所以要靠短的有效期限,加上回總部續約時把關。
期限越短越安全,但回總部的次數越多;高風險的動作,就另外問總部一次。
騙子的三個招數
最後一關。印章、公告欄都很安全,但如果分店檢查得太隨便,騙子還是有機可乘。
每一招,都有一間「笨分店」和一間「聰明分店」。看看差在哪裡。
第一招:「這張不用蓋章」
騙子把抬頭的蓋章方式改成 none(不蓋章),內容改成管理員,第三段乾脆留空。
笨分店照著通行證自己寫的方式檢查,被牽著鼻子走。聰明分店只接受事先講好的蓋章方式。
第二招:拿別間分店的通行證
騙子手上有一張真的通行證,但它是給相簿分店用的。他拿去記帳分店試試看:
章是真的,但通行證上寫著「給相簿用」。只看章不看收件人,就會收下不屬於自己的通行證。
第三招:過期的通行證
騙子撿到一張半小時前就過期的通行證,章也是真的:
檢查時間時,聰明分店會留一點點寬限(例如 30 秒),因為每台電腦的時鐘多少有誤差,但不會寬限到半小時。
聰明分店的檢查清單
把三招的教訓整理起來,一間聰明分店收到通行證時,會檢查這些:
- 蓋章方式是事先講好的那一種,不聽通行證自己說
- 用公告欄上、編號對得上的印鑑證明,比對第三段的章
- 發證的是自己認識的總部(iss)
- 收件人是自己這間分店(aud)
- 還沒過期(exp),只留一點點時鐘寬限
真實世界
寫成程式,大概就是這幾行(用的是 jose 這個工具):
const JWKS = createRemoteJWKSet(new URL(
'https://auth.example.com/.well-known/jwks.json'));
const { payload } = await jwtVerify(token, JWKS, {
algorithms: ['EdDSA'],
issuer: 'https://auth.example.com',
audience: 'ledger',
clockTolerance: 30,
});
你走完整條街了
回頭看看這一路:
網站很健忘,所以要給你通行證。通行證分成三段,內容誰都能讀,所以要蓋章防偷改。章用私鑰蓋、用公鑰比對,公鑰貼在公告欄上讓分店自己抄。印章可以照順序換,通行證要短效,分店要仔細檢查。
這整套,就叫做 JWKS 模式。
這一課學到的
騙子最常鑽的三個洞:相信通行證自己說的蓋章方式、不檢查收件人、不檢查到期時間。把清單上的每一項都檢查到,就能全部擋下。
恭喜你,小明,整條闖關街都走完了!