其它內容
-一篇文章搞懂 bcrypt、JWT、jsonwebtoken、簽章與加密
this.web

如果你是軟體工程師,但從來沒有搞懂登入系統是怎麼設計的,這篇文章想先帶你了解幾個觀念,包括 bcrypt、JWT、jsonwebtoken、簽章與加密。
讓你不管是遇到登入需求、要串接前後端驗證機制,還是要讓 AI 幫你開發時,都能分得清楚每個名詞到底在做什麼、彼此的關係是什麼,以及哪些地方最容易搞混。
這篇文章會用登入流程的角度,依序講解:
- bcrypt
- JWT
- Base64URL
- jsonwebtoken
- stateless / stateful
- session
那我們就開始吧!
一、bcrypt 是什麼?不是加密
bcrypt 的角色
bcrypt 用來處理密碼的,
在資料庫中,我們不會直接儲存用戶的密碼,因為如果被有心人士入侵資料庫,那所有人的資料都會外洩,
因此,我們需要 bcrypt 幫我們做一個不可逆的密碼轉換。
比如密碼是:123456,經過 bcrypt 後,密碼就會變成類似這樣:$2b$10$8QvJYF9m1G0nQmRz0XlS3eN1QvWmK7x0wM4Jf3mY9nG5xT2cL8p6W
這種把任意資料轉換成一段不可逆字串的運算方式,被稱為** Hash(雜湊)**,bcrypt 就是一種 password hash function,專門用來實現密碼雜湊的工具。
只不過 bcrypt 除了雜湊以外,還會搭配加鹽,加鹽的意思是加入一段隨機字串和密碼一起進行 hash,概念類似於:hash(password + salt),如果沒有加鹽,那相同的密碼會 hash 出相同的結果。
不過我們不需要看懂這串字在幹嘛,只要知道資料庫裡存的不是原始密碼,而是這串文字。
假設註冊流程是這樣:
- 使用者註冊時輸入密碼
123456 - 後端用 bcrypt 把它轉成一串文字
- 資料庫儲存的是這段被轉換後的文字,不是明文密碼
到了登入時:
- 使用者再次輸入密碼
123456 - 後端不是拿明文密碼去解密
- 而是用 bcrypt 的 compare 機制,檢查這次輸入的密碼能不能對上資料庫那串文字
- 對得上就登入成功,對不上就失敗
也就是說,除了你自己,系統和開發者根本不需要知道你的原始密碼,我們只需要知道你這次輸入的密碼,能不能和之前存下來的資料對上就好了。
注意 bcrypt 不是加密,因為它不能被解密,即使拿到雜湊值也無法還原密碼。
二、JWT 是什麼?也不是加密
JWT(JSON Web Token)是一種 Token 的格式與規範,用來:
- 承載身分資訊(claims)
- 證明這份資料沒有被竄改
- 證明 token 是由可信的一方簽發
JWT 預設是不加密內容的,它由三段組成,分別是:
header.payload.signature
其中只有 signature 是安全核心,前兩段通常長這樣:
header
header 用來描述這顆 JWT 的基本資訊,常見內容例如:
{
"alg": "HS256",
"typ": "JWT"
}alg:簽章演算法,例如HS256、RS256typ:通常是JWT
payload
payload 用來放 claims,也就是這顆 token 想傳遞的資料,例如:
{
"sub": "123",
"role": "admin",
"iat": 1710000000,
"exp": 1710003600
}sub:這顆 token 代表誰,通常是 user idrole:角色或權限資訊iat:簽發時間exp:過期時間
要注意的是,payload 是可被讀取的資料,它可不是什麼保險箱,任何人拿到 JWT 都能解碼出攜帶的資料(payload)。
因此它適合放識別與授權判斷需要的資訊,例如用戶名稱,千萬不要放密碼、身分證字號、信用卡等敏感內容。
補充:更準確應該說,多數 JWT 實作是 JWS(簽章),不是加密。但 JWT 規範也支援 JWE(加密)。
三、Base64URL 在 JWT 中的角色
那 JWT 裡的 header 和 payload 是怎麼被儲存的呢?
這就要講到 Base64URL。
不過在講 Base64URL 之前,要先知道什麼是 Base64。
什麼是 Base64?
Base64 是一種編碼方式,作用是把原本的文字資料,轉成只包含英數字和少數符號的字串。
它不是在保護資料,只是換一種比較方便傳輸的寫法。
例如一段 JSON:
{
"sub": "123",
"role": "admin"
}可以被編碼成一串 Base64 文字,這樣在網路傳輸時會比較方便處理。
而 Base64URL 是把被編碼成 Base64 文字的資料:變成可以安全放在 HTTP header / cookie / URL 裡的字串
可以把 Base64URL 理解成「Base64 的 URL / Header 安全版本」。
一般 Base64 會用到 +、/、= 這些字元,但這些字元放進 URL、cookie、HTTP header 時有時會造成額外處理上的麻煩,因此 JWT 改用 Base64URL:
- 把
+換成 - 把
/換成_ - 常常省略尾端的
=
所以它本質上只是編碼格式,用途是讓字串更適合在網路傳輸,不是拿來保護內容。
它和 JWT 的演算法是什麼關係?
這裡很容易搞混,因為 JWT 裡同時出現了 Base64URL 和 alg,但這兩者做的是完全不同的事:
- Base64URL:負責編碼 header 和 payload,讓它們變成適合傳輸的字串
alg:負責簽章演算法,例如HS256、RS256,用來產生與驗證 signature
也就是說,Base64URL 不是加密演算法也不是簽章演算法,只是把資料格式轉成字串格式。
真正和安全性直接相關的,是後面用 alg 產生出來的 signature,不是 Base64URL 本身。
四、簽章(Signature)是什麼?和加密差在哪
在上面有提到, JWT 中的 header 有 alg 用來表示簽章算法,不知道你有沒有想過,這個簽章和加密有什麼不同呢?
加密(Encryption)
目的:保密
- 沒有金鑰,就看不懂內容
- 可以解密還原
- 用在 HTTPS、資料保護
簽章(Signature)
目的:完整性 + 真實性
- 內容看得到
- 但不能被偷改
- 能確認是誰簽的
更精確地說,簽章讓接收方能驗證內容是否被修改過。
如果有人改了 header 或 payload,原本的 signature 通常就會失效,伺服器在驗證時就能發現這顆 token 不合法,然後拒絕使用它。
所以白話一點說:JWT 不是把內容藏起來,而是在內容下面蓋一個防偽章。
大家都看得到內容,但如果有人偷偷改內容,這個防偽章就會對不上,伺服器一驗就知道這張 token 是假的。
五、jsonwebtoken 這個 library 在做什麼?
那我們要怎麼做出 JWT 呢?
當然不可能自己去寫簽章算法啦,所以就可以使用 jsonwebtoken ,他是一個 JWT 規範的實作工具,會幫我們處理:
1. 簽發 token(sign)
- JSON 序列化
- Base64URL 編碼
- 使用指定演算法產生 signature
- 組合成 JWT 字串
2. 驗證 token(verify)
- 驗 signature 是否正確(內容有無被修改過)
- 確保 token 未被竄改、未過期
3. 解析 token(decode)
- 不驗證
- 只用於反向解析出 payload 的內容
六、session 是什麼?
除了 bcrypt、JWT 等,還有一個名詞經常出現在登入系統中,那就是 session。
session 可以把它理解成:使用者登入後,伺服器替這次登入建立的一份「登入狀態的紀錄」。
典型流程是:
- 使用者登入成功
- 伺服器建立一筆 session,存到記憶體、Redis 或資料庫
- 伺服器把 session id 回傳給瀏覽器,通常放在 cookie
- 之後每次 request,瀏覽器都帶上 session id
- 伺服器根據 session id 找回這位使用者的登入狀態
- 這樣我們就能判斷用戶有沒有登入
session 很常搭配 cookie 使用,瀏覽器會自動帶上 session id;JWT 則不一定,有些系統會把 JWT 放在 cookie,也有些會放在 Authorization header。
所以更精確地說,重點不是「它放在哪裡」,而是:
- session:後端拿到 session id 後,要回頭查 server 端保存的狀態
- JWT:後端拿到 token 後,先驗簽,再決定能不能相信其中的內容
而 session 和 JWT 最大的差異在於:
- session:狀態直接存在 server 中
- JWT:狀態直接放進 token,由 server 驗簽後信任內容
因此 session 就是所謂的 stateful, 而 JWT 常被稱為 stateless。
所謂 stateful,意思是:伺服器自己有記住「這個人目前的登入狀態」。
例如 session id 只是鑰匙,真正的使用者資料、登入時間、權限或其他狀態,都還存放在 server 資料庫中。每次 request 來時,server 都要根據這把鑰匙把那份狀態找出來。
相對地,JWT 之所以常被叫做 stateless,是因為伺服器理論上不一定需要另外保存這份登入狀態,只要驗簽成功,就能直接相信 token 裡的內容。
不過實務上只要你加入 refresh token 等機制後,通常又會回到某種程度的 stateful。
總結
相信看到這邊,你對這些在登入、驗證系統中常見的名詞,有一定程度的了幾了,這邊最後總結一下:
- bcrypt:驗證你知不知道密碼
- JWT:證明你已登入,且資料沒被改
- jsonwebtoken:JWT 的生產與驗證工具
- Base64URL:把資料變成適合放進 URL、cookie、header 的格式,但不是安全機制
- 簽章 ≠ 加密:簽章用來判斷資料有沒有被修改過,加密用來保護資料
希望這篇文章,有幫你了解關於驗證、授權等系統的相關概念~!