剛才看了learnku的另一篇文章:Laravel專案被入侵了,請問該如何應對和解決呢?,題主懷疑是系統的Token洩露導致的,JWT版本號是"tymon/jwt-auth": "^1.0"
,然後我去本地看了看我的依賴,發現和題主的元件和版本一樣。
於是我的擔憂來了……所以!無論如何要避免此類事情發生!
JWT組成
眾所周知,JWT是由header
、payload
、signature
三者透過.
拼接生成的。
如圖所示
- 紅色部分代表 header,主要存放JWT的加密方式等核心,由base64加密形成。
- 紫色部分代表 payload,主要存放使用者態資訊,JWT過期時間等,由base64加密形成。
- 藍色部分代表 signature,這個是根據
header
+payload
的拼接再加上secret經過某種方式加密形成的(核心)。
JWT生成
本著學習的心態瞭解一下PHP如何生成JWT,一是重新瞭解一下JWT,二是想從原理上分析JWT可能存在的問題。
// 現在我有一個已生成的JWT字串
$token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
// 解析$token中第一段取出header
$header = '{"alg": "HS256", "typ": "JWT"}'
// 解析$token中第二段取出payload
$payload = '{"sub": "1234567890","name": "John Doe","iat": 1516239022}'
好了,JWT中前兩個已經被base64解析出來了,前兩個由於是base64方式加密,相當於明文傳輸,所以大家不要將敏感資訊放到裡面去,不然很容易被駭客抓包攔截到,從而獲取或修改使用者的敏感資訊。
那麼signature(JWT的核心校驗)是怎麼生成的呢?帶著疑問我去了一趟jwt.io。
發現生成規則後,自己動手豐衣足食……
然後我拿著剛才生成的header
和payload
開啟了線上金鑰生成,假設我的金鑰為:your-256-bit-secret
,按照理論來說應該生成出來的值為:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
以對應jwt.io上signature
的值。
這裡有一個大坑
我生成了個什麼東西!!!!
然後經過一番周折發現無論如何生成的都是小寫英文加數字的組合……不符合邏輯啊
實在不行了,我去下載了"thans/tp-jwt-auth": "^1.1"
的compser包,看看別人怎麼生成的。
不要問我為什麼選這個包,我隨便找的。。。
翻閱良久,終於找到生成signature
的核心程式碼:hash_hmac
,從沒用過這個函式,然後在官方文件,簡單看了一下介紹並分析了一下第四個引數:
true
輸出原始二進位制資料false
輸出小寫 16 進位制字串。
然後煥然大悟,知道為什麼我在線上金鑰生成生成的資料對不上了,網站預設是生成的16進位制的字串。
然後繼續向下走,發現生成原始二進位制資料也對不上,沒關係繼續看原始碼,然後發現問題。
加密之後再次生成,發現還是對不上……
對比之後發現這裡有一個小坑:
- 應該生成:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- 實際生成:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV/adQssw5c
經過翻閱原始碼發現,此base64並非原生base64,話不多說上圖,刪掉了等號,替換了加號和斜槓,不知道為什麼這麼做,莫非是是RFC規範這麼做的?。
好了,這下就完全沒問題了,拿到jwt.io校驗一下,嗯透過了,不錯。
總結
一直都在用JWT做介面授權,只是對JWT原理略有耳聞,還沒有這麼深度的分析過,經過這次對JWT的瞭解,發現最敏感的地方就在SECRET
。如果SECRET
沒有洩露的話理應來說不會造成Token的安全風險,逆向的話更是無稽之談。所以至於題主Token洩露是什麼原因,排除伺服器掛馬、使用者裝置中毒、商業惡性競爭的話,我也沒分析出來。不過大家在產品上線後一定要重新生成SECRET
,防止SECRET
洩露。今天也算沒白活,又Get到一個知識點。
本作品採用《CC 協議》,轉載必須註明作者和本文連結