JSON Web Tokens(JWT)的理解

前言

雖然前兩年系統(tǒng)中就已經(jīng)應(yīng)用了JWT作為token用來鑒權(quán)認(rèn)證等,大概知道那么回事雷激,但是經(jīng)常交流過程中袜匿,面對別人的疑問沒法給一個深入的解答,所以重新梳理了下JWT相關(guān)知識诫给。

1.什么是JWT?

JWT官網(wǎng)
JSON Web Token (JWT)是一個開放標(biāo)準(zhǔn)(RFC 7519)香拉,它定義了一種緊湊且自包含的方式啦扬,以JSON對象的方式在各方之間安全地傳輸信息,因?yàn)槭腔跀?shù)字簽名所以可以進(jìn)行驗(yàn)證和信任凫碌,常用的算法比如有HMAC扑毡、RSA等等。

2.JWT數(shù)據(jù)結(jié)構(gòu)

JWT由三部分組成,以"點(diǎn)"(.)作為分隔符盛险,看起來格式這樣的xxx.yyy.zzz

接下來看一下這三部分的具體構(gòu)成:

  • Header
    Header是JWT的第一部分费什,包含算法類型和token類型的說明方援,舉例如下,算法是用的HS256指的是HMACSHA256,token類型是JWT言沐。
    HMACSHA256不了解?可以看看對算法介紹的這一篇密碼學(xué)相關(guān)知識梳理
    Base64Url不了解作煌?Base64和Base64Url區(qū)別是什么清蚀?下文會對Base64和Base64URL做一些簡單介紹。
例子:Header內(nèi)容
{
 "alg": "HS256",
 "typ": "JWT"
}
對該json進(jìn)行Base64Url編碼得到
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9,也就是xxx.yyy.zzz的xxx部分的值。
  • Payload:載荷
    Payload是JWT第二部分祟牲,我們把數(shù)據(jù)放在這部分,舉例如下
例子:Payload內(nèi)容
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
對該json進(jìn)行Base64Url編碼得到
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
  • Signature:簽名
    Signature是JWT第三部分隙畜,是對前兩塊內(nèi)容的簽名值,比如以簽名算法HMACSHA256為例
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
按照上面計(jì)算規(guī)則:
 base64UrlEncode(header) + "."+base64UrlEncode(payload)=xxx.yyy
也就是說第三部分的值就是對“xxx.yyy”進(jìn)行HMACSHA256摘要計(jì)算,這里secret假設(shè)等于“123456789”
計(jì)算出來的第三部分值:S2ZL7D-D3VeduQ44Cy2qLRFxHV43gRGSZtlfJ2MJ57g

最后把上面三部分拼接到一起組成完整的JWT如下说贝,從上面的計(jì)算規(guī)則我們可以發(fā)現(xiàn)议惰,JWT的安全性其實(shí)就是基于算法的原理,比如用的HMACSHA256乡恕,那么密鑰就是安全的保證言询,別人拿不到密鑰就無法偽造,無法篡改JWT傲宜。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.S2ZL7D-D3VeduQ44Cy2qLRFxHV43gRGSZtlfJ2MJ57g

2.1一些理解:

  • Q1:Payload是否可以存敏感數(shù)據(jù)倍试?
  • A1:不能,Header和Payload都只是對數(shù)據(jù)進(jìn)行Base64Url編碼而已蛋哭,了解Base64的話县习,應(yīng)該知道這個不是加密,第三方拿到編碼數(shù)據(jù)可以直接解碼谆趾,所以不要放任何敏感數(shù)據(jù)躁愿,除非額外對數(shù)據(jù)又進(jìn)行加密處理。
  • Q2:第三方是否可以偽造JWT沪蓬?是否可以篡改Payload里面的數(shù)據(jù)彤钟?
  • A2:從上面第三部分Signature簽名值計(jì)算規(guī)則,我們可以看到跷叉,是用HMACSHA256算法以及密鑰key計(jì)算Header和Payload的摘要值逸雹,密鑰key是服務(wù)端私有的,理論上攻擊者沒有密鑰key就無法生成出一樣的簽名值云挟,所以結(jié)論是無法偽造jwt梆砸,同樣的篡改Payload里面的數(shù)據(jù),服務(wù)端計(jì)算出來的簽名值就會不匹配园欣,這樣就可以認(rèn)為被篡改了帖世,直接拒絕服務(wù),所以密鑰key是關(guān)鍵沸枯,不能泄露日矫。
  • Q3:假設(shè)如下截圖中消息是xxx.yyy的值,HMACSHA256簽名后在進(jìn)行Base64Url編碼得到的是如下截圖中的結(jié)果A'還是結(jié)果B绑榴?
  • A3:答案是B哪轿,詳細(xì)解釋如下:
    如下截圖中消息是base64UrlEncode(header) + "." +base64UrlEncode(payload),也就是待簽名內(nèi)容翔怎,使用密鑰key通過計(jì)算窃诉,結(jié)果A是HMACSHA256計(jì)算的摘要值字節(jié)數(shù)組轉(zhuǎn)十六制的值64個字符(sha256計(jì)算摘要值是256bit,1個字節(jié)8bit,256bit對應(yīng)32個字節(jié)褐奴,1個字節(jié)用2位16進(jìn)制表示按脚,所以結(jié)果A是64位),然后對結(jié)果A進(jìn)行Base編碼得到結(jié)果A' 88個字符(64位十六進(jìn)制讀取的時候每一位當(dāng)做一個字符讀榷囟),結(jié)果B是對HMACSHA256計(jì)算出來的32個字節(jié)原始二進(jìn)制直接進(jìn)行Base64編碼得到的是44個字符辅搬,結(jié)果B是才是正確的流程,結(jié)果A為什么會長度多一倍呢脖旱?因?yàn)楹灻?2個字節(jié)轉(zhuǎn)成16進(jìn)制后堪遂,在計(jì)算Base64的讀取十六進(jìn)制的時候是以字符讀取,變成了64個字節(jié)萌庆,一出一進(jìn)長度翻了一倍溶褪。

3.Base64和Base64Url

3.1Base64算法

Base64主要是對給定的字符和字符編碼(如ASCII碼,UTF-8碼)對應(yīng)的十進(jìn)制數(shù)為基準(zhǔn)践险,做編碼操作:
1.將給定的字符串以字符為單位轉(zhuǎn)換為對應(yīng)的字符編碼(如ASCII碼)
2.將獲得的字符編碼轉(zhuǎn)換為二進(jìn)制碼
3.對獲得的二進(jìn)制碼做分組轉(zhuǎn)換操作猿妈,每3個8位二進(jìn)制碼為一組,轉(zhuǎn)換為每4個6位二進(jìn)制碼為一組(不足6位時地位補(bǔ)0)巍虫,這是一個分組變化的過程彭则,3個8位二進(jìn)制碼和4個6位二進(jìn)制碼的長度都是24位(38=46=24)
4.對獲得的4個6位二進(jìn)制碼補(bǔ)位,向6位二進(jìn)制碼添加2位高位0占遥,組成4個8位二進(jìn)制碼
5.將獲得的4個8位二進(jìn)制碼轉(zhuǎn)換為十進(jìn)制碼
6.將獲得的十進(jìn)制碼轉(zhuǎn)換為Base64字符表中對應(yīng)的字符
舉例如下:ASCII碼字符編碼
對字符串“A”進(jìn)行Base64編碼俯抖,如下表示:

字符                     A
ASCII碼                  65
二進(jìn)制碼                 01000001
4-6二進(jìn)制碼              010000      010000
4-8二進(jìn)制碼              00010000    00010000
十進(jìn)制碼                 16          16
字符表映射碼              Q          Q           =       =

字符“A‘經(jīng)過Base64編碼后得到"QQ=="這樣一個字符串,Base64是以4個字符為單位瓦胎,其長度只能是4個字符的整數(shù)倍芬萍,不滿足時就用等號補(bǔ)位。

3.2 Base64Url

查看Base64字符映射表我們可以知道有一些字符比如"/"搔啊、“+”柬祠、“=”,像這種字符在Url中有特殊的意義坯癣,所以我們需要替代這些字符瓶盛,替代規(guī)則是“-”替代“+”,"_"替代“/”,"="直接去掉最欠,這就是Base64Url編碼方式示罗。

  • Base64Url編碼的流程
1.明文使用BASE64進(jìn)行編碼
2. 在BASE64的基礎(chǔ)上進(jìn)行以下的編碼:
   去除尾部的"="
   把"+"替換成"-"
   把"/"替換成"_"
  • Base64Url解碼的流程
1.替換字符
    把"-"替換成"+"
    把"_"替換成"/"
   (計(jì)算Base64Url編碼長度)%4
    結(jié)果為0,不做處理
    結(jié)果為2芝硬,字符串末尾添加"=="
    結(jié)果為3蚜点,字符串末尾添加"="
 2、使用Base64解碼密文拌阴,得到原始的明文

3.2.1Base64Url解碼問題

交流的時候有個同事剛好提出為什么補(bǔ)等號的時候绍绘, (計(jì)算Base64Url編碼長度)%4結(jié)果為0,2,3陪拘,沒有為1的情況厂镇?
接下來看一下這個計(jì)算過程,前面提到Base64編碼規(guī)則每3個8位二進(jìn)制碼為一組左刽,轉(zhuǎn)換為每4個6位二進(jìn)制碼為一組(不足6位時地位補(bǔ)0)捺信,假設(shè)我們對一組字節(jié)編碼,比如22個字節(jié)欠痴,每三個字節(jié)一組迄靠,最后剩下一個字節(jié)(22mod3=1),23個字節(jié)分組后剩下2個字節(jié)(23mod3=2),21個字節(jié)則正好分成7組喇辽,所以分組過程中只可能剩1個字節(jié)或者2個字節(jié)掌挚,下面對剩1個和2個字節(jié)的分析

  • 1個字節(jié)
    從前面對字符"A"編碼過程也可以看到,如果一個字節(jié)比如01000001菩咨,拆成4-6二進(jìn)制的時候是010000和010000(本來是拆成6位010000和01吠式,不足6位的補(bǔ)0),4-8二進(jìn)制變成00010000和00010000抽米,然后在轉(zhuǎn)10進(jìn)制然后從Base64映射對應(yīng)的字符得到兩個字符QQ奇徒,Base64是4個字符位單位,所以補(bǔ)兩個"=="缨硝。
  • 2個字節(jié)
    從上面剩1個字節(jié)的分析可以很容易的看出摩钙,2個字節(jié)拆成4-6二進(jìn)制的時候?qū)?yīng)3個4-6,4-8二進(jìn)制也是3個查辩,最后得到字符3個胖笛,補(bǔ)一個“=”號。
    所以轉(zhuǎn)成Base64后宜岛,可能剛好分組长踊,或補(bǔ)1個等號或2個等號這三種,不存在補(bǔ)3個等號的萍倡。

3.3擴(kuò)展的一些思考

我們將JWT用作系統(tǒng)token機(jī)制身弊,用戶登錄后服務(wù)端頒發(fā)token,后續(xù)請求頭帶上token列敲,服務(wù)端檢驗(yàn)該token是否合法來判斷用戶的合法性阱佛。

  • 對于現(xiàn)在很多單頁面應(yīng)用比如基于AngluarJS,Vue戴而,拿到token后存在了localstorage中凑术,后續(xù)請求在從localstorage中取出,這樣是否安全所意?是否有更好的方案淮逊?
  • 我們在以前pc時代通過session催首,cookie機(jī)制進(jìn)行會話跟蹤,那這兩種機(jī)制本質(zhì)上的差別是什么泄鹏?
    這兩個問題因?yàn)檫€沒有完全想明白也沒有一個完美的解決方案郎任,所以暫時拋出來記錄一下。

4.附錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末备籽,一起剝皮案震驚了整個濱河市涝滴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胶台,老刑警劉巖歼疮,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诈唬,居然都是意外死亡韩脏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門铸磅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赡矢,“玉大人,你說我怎么就攤上這事阅仔〈瞪ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵八酒,是天一觀的道長空民。 經(jīng)常有香客問我,道長羞迷,這世上最難降的妖魔是什么界轩? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮衔瓮,結(jié)果婚禮上浊猾,老公的妹妹穿的比我還像新娘。我一直安慰自己热鞍,他們只是感情好葫慎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著薇宠,像睡著了一般偷办。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昼接,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天爽篷,我揣著相機(jī)與錄音,去河邊找鬼慢睡。 笑死逐工,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的漂辐。 我是一名探鬼主播泪喊,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼髓涯!你這毒婦竟也來了袒啼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤纬纪,失蹤者是張志新(化名)和其女友劉穎蚓再,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體包各,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摘仅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了问畅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娃属。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖护姆,靈堂內(nèi)的尸體忽然破棺而出矾端,到底是詐尸還是另有隱情,我是刑警寧澤卵皂,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布秩铆,位于F島的核電站,受9級特大地震影響灯变,放射性物質(zhì)發(fā)生泄漏豺旬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一柒凉、第九天 我趴在偏房一處隱蔽的房頂上張望族阅。 院中可真熱鬧,春花似錦膝捞、人聲如沸坦刀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲤遥。三九已至,卻和暖如春林艘,著一層夾襖步出監(jiān)牢的瞬間盖奈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工狐援, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钢坦,地道東北人究孕。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像爹凹,于是被迫代替她去往敵國和親厨诸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容