iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Claude AI

AI 負責答,我負責讓答案可信——公部門工程師的 30 天 Claude 協作紀律系列 第 19 篇

Day 19:金鑰確實被猜中了,但報告那張「驗證通過」的截圖,怎麼看怎麼怪

  • 分享至 

  • xImage
  •  

Day 19:金鑰確實被猜中了,但報告那張「驗證通過」的截圖,怎麼看怎麼怪

前兩天判讀的是弱掃報告。今天這份份量更重:一份外部白帽單位出具、蓋著「高風險」的滲透測試報告,說系統的 JWT(一種帶簽章的身分權杖)簽章金鑰太弱,攻擊者可以偽造任意身分。

先講結論:這個弱點是真的。 金鑰確實太弱、確實被猜了出來,報告沒有冤枉我。但我盯著報告裡那張「驗證通過」的截圖,怎麼看都覺得哪裡不對——它秀出來的那個「證明」,邏輯上好像根本沒有證明到它想證明的東西。這篇就是這個「怪」的來龍去脈,以及一個非資安專業的人,可以怎麼靠一個工具把這種疑問查到水落石出。

那張截圖為什麼怪

報告展示的流程大致是:拿到一組系統發的合法 token、解碼看到裡面的帳號;接著測試者用一個很弱的字串(就叫它 secret)當金鑰,把帳號改成 admin、重新簽出一組新 token,然後驗證這組新 token——畫面顯示「簽章通過」。報告據此判定金鑰是弱密鑰、風險「高」。

我卡住的地方是:他用 secret 這把金鑰簽了一組 token,再用 secret 這把金鑰去驗這組 token——這不是廢話嗎? 我自己拿一把鑰匙鎖門、再用同一把鑰匙開門,當然開得了,這能證明什麼?於是我把這個疑問丟給 AI。

AI 第一輪:答的是「怎麼猜」,不是「這算不算證明」

AI 第一輪解釋了離線字典攻擊:JWT 的簽章驗證可以在自己電腦上離線做,不碰伺服器、不會被鎖定,所以可以拿一份常見弱密鑰字典逐一去試,直到某個字算出來的簽章跟 token 對上——secret 這種開發者偷懶的預設值,字典裡一定有。

這個回答本身沒錯,但它答的是「一把弱金鑰怎麼被猜出來」,還沒回答我真正卡住的:報告秀的那個「自己簽、自己驗」的展示步驟,到底能不能算數。所以我把問題講得更精確。

逼近核心:我不是質疑金鑰弱不弱,是那個展示邏輯是循環的

我把話說白:先不管暴力破解——就報告秀的那一步,他拿 secret 簽新 token、再用 secret 驗,這在邏輯上必然成功,跟金鑰強不強根本無關。AI 這次接住了,而且點破:對,這是同義反覆(circular)。「我知道密碼是什麼,所以我能用這個密碼登入」——這不是漏洞證明,這只是套套邏輯。

那,一個邏輯上真正站得住的證明,該長什麼樣?這裡就是這篇最值得學的一段。

真正的證明:差別只在一個字——「原始」

關鍵在 JWT 的簽章是怎麼算出來的。它用的 HS256 演算法,簽章是這樣產生的:

簽章 = HMAC-SHA256( base64(header) + "." + base64(payload) , 金鑰 )

HMAC 是確定性函數:同一段訊息配同一把金鑰,永遠算出同一個簽章,沒有隨機性。正因為如此,有一個乾淨俐落的驗證法——而這個方法,其實正是我一開始腦中假設「報告應該是這樣做」的那個流程:

  1. 拿系統原本發的那張合法 token,取出它的 header 和 payload(這兩段本來就能直接解碼看到)
  2. 用候選金鑰 secret,對這段原封不動的原始 header + payload 重新簽一次
  3. 看算出來的簽章,跟原始 token 那段簽章是不是逐字相同

如果相同,就證明了系統當初就是用 secret 簽的。 因為要「重現一個伺服器已經簽好的簽章」,除非你手上的金鑰正是它用的那把,否則做不到——要湊出另一把不同金鑰、卻對同一段訊息算出相同 HMAC,是密碼學上不可行的碰撞。

看出差別了嗎?就差在一個字:原始。

簽的是哪段訊息、驗的是哪個簽章 能不能證明
報告秀的那步 自己新造一組 token,驗自己簽的 ❌ 不能,自簽自驗必然過
真正的證明 拿原始 token 的內容重簽,比對原始簽章 ✅ 能,你在重現伺服器簽過的東西

自己造一個新 token 再驗自己,兩邊金鑰都是你的,當然通過,什麼都沒證明;而比對原始簽章,是拿系統已經簽好、你沒參與製造的那個結果當基準——能重現它,才代表你手上這把,就是它用的那把。

(一個學理上的小註腳:嚴格說「簽章相符」不能百分之百排除「宇宙中剛好存在另一把金鑰也算出同一值」,但那是天文數字級、湊不出來的碰撞,鑑識上直接當證明沒問題。)

所以報告到底怎麼回事

想通這個,答案就清楚了:報告的結論是對的(金鑰確實是 secret、確實弱),但它秀出來的證明步驟不完整——它大概是漏貼了「用 secret 驗證原始 token 成功」那張關鍵截圖,只放了後面「既然金鑰是 secret,那就來偽造一個 admin」的展示。於是我讀報告時,看到的就變成一段「自己簽、自己驗」的循環論證。弱點是真的,只是舉證記錄少了最關鍵的那一步。

我後來沒有去追測試單位補件——金鑰本來就該換、也已經換掉了,弱點實質上排除了,追證明步驟的完整性意義不大。

這篇其實不太算「協作」——但它是這系列另一種常見的樣子

老實說,這篇跟前面很多篇不一樣,它沒什麼「人跟 AI 來回把東西做出來」的協作味道。我沒有糾正 AI 什麼,AI 也沒幫我把什麼做完。真正發生的事更簡單:我帶著一個「這報告怎麼看都怪」的直覺,用 AI 把背後的密碼學原理問清楚,確認我這個直覺到底站不站得住。

但這恰恰是這系列想講的另一面。人的價值,不總是「做」或「抓錯」,有時候就只是那個**「不因為它蓋了高風險大印、出自專業白帽單位,就照單全收」的直覺**——覺得哪裡怪,就不放過。而 AI 的價值,是把一個我不熟的領域(密碼學)的原理,講到能讓我確認自己那個模糊直覺是對是錯。這兩件事湊起來,才讓一份看起來理所當然的報告,被讀出「它的證明其實漏了一步」。如果我沒有那個直覺,再強的 AI 也不會主動跳出來說「欸這份報告的舉證不完整喔」;如果我沒有 AI,那個「怪怪的」感覺大概就停在心裡、不了了之。

根因與改善:如果你手上也有一組 JWT

既然是教學,把這個弱點的根因跟該怎麼修補講清楚。

根因:JWT 的簽章金鑰用了弱密鑰。最常見的成因有兩種——一是直接沿用了教學文件、線上除錯工具的預設示範值(secret、your-256-bit-secret 這類),上線忘了改;二是把金鑰硬編碼寫死在原始碼裡,一旦原始碼外流(公開的 repo、前端 JS、設定檔),金鑰就等於公開。

改善方向(由基本到進階):

  • 換成高強度隨機金鑰:用足夠長度、足夠亂度的隨機字串(至少 256 bit),不要用任何有意義的字、專案名稱或預設值。
  • 金鑰不要進原始碼:放環境變數或專門的密鑰管理機制,讓金鑰跟程式碼分離,原始碼外流也不會連金鑰一起洩。
  • 定期輪替:金鑰不是設一次用到天長地久,訂一個輪替週期,並確保換金鑰時有平順的過渡機制。
  • 考慮改用非對稱簽章(RS256/ES256):對稱式的 HS256,簽發和驗證用的是同一把金鑰,任何一端被入侵、金鑰外流,攻擊者就能偽造 token;非對稱式則是私鑰只留在簽發端、驗證端只拿得到公鑰,就算驗證端整台被打穿,也偽造不出合法 token。對外服務、或 token 要給多方驗證的架構,這個提升特別值得。
  • 縮短 token 有效期:配合 refresh token 機制,把單張 token 的存活時間壓短,萬一真的外流,可被利用的時間窗也小。

明天換一組主題:從「判讀別人丟過來的報告」,轉到「合規要求真正要落地時」——通用的資安最佳實務,碰上台灣公部門的在地現實,會產生什麼落差。先從組態基準(GCB)的導入談起。


上一篇
Day 18:一個弱點,從「修好了」到「根本不在 header 上」
系列文
AI 負責答,我負責讓答案可信——公部門工程師的 30 天 Claude 協作紀律 共 19 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言