這是軟體界最常見的誤解之一:有人看到 cGFzc3dvcmQ= 這種字串,就以為資料被「加密」了。其實沒有。Base64 是編碼,不是加密 —— 搞混這兩者會導致真正的資安錯誤。我們來釐清。
這裡給的是證據,不是主張。 把 JWT 官方文件的示範 token 貼進我們的 JWT 解碼器。不提供任何密鑰,它立刻印出:
{ "alg": "HS256", "typ": "JWT" } { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }那個 token 的內容是 Base64url,而 Base64 是一種傳輸編碼、字母表是公開的 —— 完全沒有秘密參與,所以任何用它編碼的東西,只要有人願意就讀得到。簽章才是唯一需要密鑰的部分,而它防的是篡改,不是閱讀。永遠不要把機密放進 Base64 字串然後說它受保護了。
Base64 到底做了什麼
Base64 把任意位元組用 64 個可列印字元(A–Z、a–z、0–9、+、/)來表示。它的用途是傳輸:讓你把二進位或特殊字元透過只能處理文字的通道帶過去 —— email 內文、JSON 欄位、Data URI、JWT 段落等等。
關鍵是,Base64 沒有金鑰、沒有秘密。任何人都能在瞬間解回原文。試試看:把 cGFzc3dvcmQ= 貼進 Base64 工具,立刻就會得到 password。
把這個說法變成輸出。下表每一列都經過我們自己的 Base64 編碼器;把右邊任何一個值貼回同一頁、切到解碼,左邊那一欄就原樣回來。整個過程沒有任何密鑰 —— 根本沒有地方放密鑰。
| 輸入 | Base64 |
|---|---|
secret | c2VjcmV0 |
admin:password | YWRtaW46cGFzc3dvcmQ= |
{"role":"admin"} | eyJyb2xlIjoiYWRtaW4ifQ== |
Hello, World! | SGVsbG8sIFdvcmxkIQ== |
編碼 vs 加密
| 編碼(Base64) | 加密 | |
|---|---|---|
| 目的 | 讓資料能安全傳輸 | 讓資料對他人不可讀 |
| 金鑰/秘密 | 無 | 有 —— 需要金鑰 |
| 任何人都能還原? | 是,輕而易舉 | 否,只有持金鑰者 |
| 提供機密性? | ❌ 否 | ✅ 是 |
編碼談的是表示方式;加密談的是保密。它們解決完全不同的問題。
第二列不是硬湊的例子。HTTP Basic 認證送的就是這個:admin:password 變成 YWRtaW46cGFzc3dvcmQ=,標頭寫成 Authorization: Basic YWRtaW46cGFzc3dvcmQ=。任何看得到這個請求的人都讀得到密碼,這就是為什麼 Basic auth 只有在 TLS 之上才可以接受 —— 機密性是傳輸層給的,編碼一點都沒給。第三列是同一個錯誤換一套衣服:eyJyb2xlIjoiYWRtaW4ifQ== 看起來不透明,一步就解成 {"role":"admin"},所以 cookie 裡放這種值,等於讓使用者自己發權限給自己。
一個相關概念:雜湊
大家也常把 Base64 跟雜湊搞混。雜湊(如 SHA-256)是單向函數 —— 你無法從結果反推原文 —— 用於完整性校驗與密碼儲存,而非傳輸。想實驗的話,我們的 Hash 產生器會示範同一輸入永遠產生相同的固定長度指紋。
所以有三個不同的概念:
- 編碼(Base64):任何人可還原,用於傳輸。
- 雜湊(SHA-256):單向,用於完整性。
- 加密(AES、RSA…):只有持金鑰者能還原,用於保密。
要避免的資安錯誤
千萬別用 Base64 來「藏」密碼、API 金鑰或任何機敏值。因為它可被輕易還原,對機密提供的保護是零。若需要機密性,請用真正的加密(例如傳輸中用 TLS、靜態資料用 AES),並妥善儲存憑證。
判斷一件事是不是加密,有個好用的測試:問「什麼東西必須是祕密的」。對 c2VjcmV0 而言什麼都不是 —— 演算法公開、字母表公開,而且沒有任何密鑰參數需要保護。沒有祕密的加密不是加密,只是同一份資料的另一種拼法。
Base64 適合用在哪
當你確實需要把二進位或特殊資料透過文字通道傳遞時,Base64 很完美:
- 把小圖片轉成 Data URI 內嵌到 HTML 或 CSS。
- 檢視或組裝 JWT 的各段落。
- 在 JSON API 中傳遞二進位內容。
- 把特殊字元安全地放進某個值裡。
拿它做它擅長的事 —— 表示 —— 需要保密時再用加密。你可以用我們免費、在瀏覽器執行的 Base64 工具(完整支援 UTF-8)來編碼與解碼。