從JWT到CSRF

1. JWT是什么

JSON Web Token(縮寫 JWT)晕拆,一個規(guī)范用于用戶和服務(wù)器之間傳遞安全可靠的信息。原理為服務(wù)端生成一個帶有用戶標(biāo)識的令牌返回給客戶端嘀掸,客戶端請求的時候再帶上這個令牌紫岩,服務(wù)端根據(jù)這個令牌來確認(rèn)當(dāng)前用戶是誰。同時使用簽名保證數(shù)據(jù)的安全性(不被篡改)睬塌。這樣做就能省掉服務(wù)端的session記錄泉蝌,連用戶狀態(tài)都不需要再關(guān)心。


思考下可能存在的問題:
  • jwt泄露揩晴,導(dǎo)致用戶信息泄露勋陪,以及操作權(quán)被使用
    1. jwt不能涉及用戶關(guān)鍵數(shù)據(jù),如果涉及需要將jwt進(jìn)行加密硫兰。
    2. 縮短jwt有效期
    3. 使用https
    4. 重要服務(wù)進(jìn)行二次驗(yàn)證
  • jwt存儲在哪诅愚?客戶端能否統(tǒng)一處理讓所有請求帶上這個令牌?
    1. 存儲在cookie中,自動實(shí)現(xiàn)統(tǒng)一處理劫映。但沒法解決跨域問題
    2. 設(shè)在http-header中违孝,如 Authorization: Bearer <token> 。所有的http請求包含表單泳赋、ajax雌桑、同步跳轉(zhuǎn)都要加上這個header.
  • jwt偽造,如果簽名密鑰泄露出去了那么jwt就可以被偽造
    1. 簽名密鑰泄露并且被偽造token摹蘑,這個在服務(wù)端是無法感知的筹燕。只能加強(qiáng)對secret的管理,并且對重要服務(wù)進(jìn)行二次校驗(yàn)。
  • 后管怎么強(qiáng)制將某個jwt失效撒踪?無法做到類似踢出某個用戶的動作
    1. 使用JWT的方式就是存在這種問題过咬、無法解決。因?yàn)閿?shù)據(jù)都不存儲在服務(wù)端制妄。一旦頒發(fā)token只有等待失效掸绞。

2. JWT結(jié)構(gòu)

  • Header(頭部)
  • Payload(消息體)
  • Signature(簽名)

JWT由上面3個部分組成。

頭信息指定了該JWT使用的簽名算法:

header = '{"alg":"HS256","typ":"JWT"}'

HS256表示使用了 HMAC-SHA256 來生成簽名耕捞。

消息體包含了令牌的意圖:

payload = '{"sub":"admin","iat":1422779638}'//iat表示令牌生成的時間
  1. iss (issuer):簽發(fā)人
  2. exp (expiration time):過期時間
  3. sub (subject):主題
  4. aud (audience):受眾
  5. nbf (Not Before):生效時間
  6. iat (Issued At):簽發(fā)時間
  7. jti (JWT ID):編號

簽名是用base64url編碼的頭信息和消息體拼接(使用”.”分隔) 再通過私有的secret計(jì)算而來

key = 'secretkey'  
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)  
signature = HMAC-SHA256(key, unsignedToken)

最后得到整個token數(shù)據(jù)為

token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) 

3. JWT使用場景

  1. 一次性驗(yàn)證
    比如用戶注冊后需要發(fā)一封郵件讓其激活賬戶衔掸,通常郵件中需要有一個鏈接,這個鏈接需要具備以下的特性:能夠標(biāo)識用戶俺抽,該鏈接具有時效性(通常只允許幾小時之內(nèi)激活)敞映,不能被篡改以激活其他可能的賬戶…這種場景就和 jwt 的特性非常貼近,jwt 的 payload 中固定的參數(shù):iss 簽發(fā)者和 exp 過期時間正是為其做準(zhǔn)備的磷斧。

  2. restful api的無狀態(tài)認(rèn)證
    使用 jwt 來做 restful api 的身份認(rèn)證也是值得推崇的一種使用方案振愿。客戶端和服務(wù)端共享 secret弛饭;過期時間由服務(wù)端校驗(yàn)冕末,客戶端定時刷新;簽名信息不可被修改…spring security oauth jwt 提供了一套完整的 jwt 認(rèn)證體系侣颂,以筆者的經(jīng)驗(yàn)來看:使用 oauth2 或 jwt 來做 restful api 的認(rèn)證都沒有大問題档桃,oauth2 功能更多,支持的場景更豐富憔晒,后者實(shí)現(xiàn)簡單(后者的實(shí)現(xiàn)還是需要覆蓋認(rèn)證的場景藻肄。如果不認(rèn)證,jwt就沒有用戶標(biāo)識)。

  3. 使用 jwt 做單點(diǎn)登錄+會話管理(不推薦)

4. JWT特點(diǎn)

(1)JWT 默認(rèn)是不加密拒担,但也是可以加密的仅炊。生成原始 Token 以后,可以用密鑰再加密一次澎蛛。

(2)JWT 不加密的情況下,不能將秘密數(shù)據(jù)寫入 JWT蜕窿。

(3)JWT 不僅可以用于認(rèn)證谋逻,也可以用于交換信息。有效使用 JWT桐经,可以降低服務(wù)器查詢數(shù)據(jù)庫的次數(shù)毁兆。

(4)JWT 的最大缺點(diǎn)是,由于服務(wù)器不保存 session 狀態(tài)阴挣,因此無法在使用過程中廢止某個 token气堕,或者更改 token 的權(quán)限。也就是說,一旦 JWT 簽發(fā)了茎芭,在到期之前就會始終有效揖膜,除非服務(wù)器部署額外的邏輯。

(5)JWT 本身包含了認(rèn)證信息梅桩,一旦泄露壹粟,任何人都可以獲得該令牌的所有權(quán)限。為了減少盜用宿百,JWT 的有效期應(yīng)該設(shè)置得比較短趁仙。對于一些比較重要的權(quán)限,使用時應(yīng)該再次對用戶進(jìn)行認(rèn)證垦页。

(6)為了減少盜用雀费,JWT 不應(yīng)該使用 HTTP 協(xié)議明碼傳輸,要使用 HTTPS 協(xié)議傳輸痊焊。

5. JWT和cookie-session對比

JWT更關(guān)注的是實(shí)體之間安全的消息傳輸盏袄。無狀態(tài)快速響應(yīng)(不涉及第三方存儲).
cookie-session更側(cè)重的是用戶信息安全宋光、基于http協(xié)議貌矿。

如果使用JWT實(shí)現(xiàn)單點(diǎn)登錄,那么需要考慮以下幾點(diǎn)問題罪佳。

secret如何設(shè)計(jì)

jwt 唯一存儲在服務(wù)端的只有一個 secret逛漫,個人認(rèn)為這個 secret 應(yīng)該設(shè)計(jì)成和用戶相關(guān)的,而不是一個所有用戶公用的統(tǒng)一值赘艳。這樣可以有效的避免一些注銷和修改密碼時遇到的窘境酌毡。

注銷和修改密碼

傳統(tǒng)的 session+cookie 方案用戶點(diǎn)擊注銷,服務(wù)端清空 session 即可蕾管,因?yàn)闋顟B(tài)保存在服務(wù)端枷踏。但 jwt 的方案就比較難辦了,因?yàn)?jwt 是無狀態(tài)的掰曾,服務(wù)端通過計(jì)算來校驗(yàn)有效性旭蠕。沒有存儲起來,所以即使客戶端刪除了 jwt旷坦,但是該 jwt 還是在有效期內(nèi)掏熬,只不過處于一個游離狀態(tài)。分析下痛點(diǎn):注銷變得復(fù)雜的原因在于 jwt 的無狀態(tài)秒梅。我提供幾個方案旗芬,視具體的業(yè)務(wù)來決定能不能接受。

  • 僅僅清空客戶端的 cookie捆蜀,這樣用戶訪問時就不會攜帶 jwt疮丛,服務(wù)端就認(rèn)為用戶需要重新登錄幔嫂。這是一個典型的假注銷,對于用戶表現(xiàn)出退出的行為誊薄,實(shí)際上這個時候攜帶對應(yīng)的 jwt 依舊可以訪問系統(tǒng)履恩。
  • 清空或修改服務(wù)端的用戶對應(yīng)的 secret,這樣在用戶注銷后暇屋,jwt 本身不變似袁,但是由于 secret 不存在或改變,則無法完成校驗(yàn)咐刨。這也是為什么將 secret 設(shè)計(jì)成和用戶相關(guān)的原因昙衅。
  • 借助第三方存儲自己管理 jwt 的狀態(tài),可以以 jwt 為 key定鸟,實(shí)現(xiàn)去 redis 一類的緩存中間件中去校驗(yàn)存在性而涉。方案設(shè)計(jì)并不難,但是引入 redis 之后联予,就把無狀態(tài)的 jwt 硬生生變成了有狀態(tài)了啼县,違背了 jwt 的初衷。實(shí)際上這個方案和 session 都差不多了沸久。

修改密碼則略微有些不同季眷,假設(shè)號被到了,修改密碼(是用戶密碼卷胯,不是 jwt 的 secret)之后子刮,盜號者在原 jwt 有效期之內(nèi)依舊可以繼續(xù)訪問系統(tǒng),所以僅僅清空 cookie 自然是不夠的窑睁,這時挺峡,需要強(qiáng)制性的修改 secret。在我的實(shí)踐中就是這樣做的担钮。

續(xù)簽問題

續(xù)簽問題可以說是我抵制使用 jwt 來代替?zhèn)鹘y(tǒng) session 的最大原因橱赠,因?yàn)?jwt 的設(shè)計(jì)中我就沒有發(fā)現(xiàn)它將續(xù)簽認(rèn)為是自身的一個特性。傳統(tǒng)的 cookie 續(xù)簽方案一般都是框架自帶的箫津,session 有效期 30 分鐘狭姨,30 分鐘內(nèi)如果有訪問,session 有效期被刷新至 30 分鐘苏遥。而 jwt 本身的 payload 之中也有一個 exp 過期時間參數(shù)送挑,來代表一個 jwt 的時效性,而 jwt 想延期這個 exp 就有點(diǎn)身不由己了暖眼,因?yàn)?payload 是參與簽名的,一旦過期時間被修改纺裁,整個 jwt 串就變了诫肠,jwt 的特性天然不支持續(xù)簽司澎!

如果你一定要使用 jwt 做會話管理(payload 中存儲會話信息),也不是沒有解決方案栋豫,但個人認(rèn)為都不是很令人滿意

  • 每次請求刷新 jwt

jwt 修改 payload 中的 exp 后整個 jwt 串就會發(fā)生改變挤安,那…就讓它變好了,每次請求都返回一個新的 jwt 給客戶端丧鸯。太暴力了蛤铜,不用我贅述這樣做是多么的不優(yōu)雅,以及帶來的性能問題丛肢。

但围肥,至少這是最簡單的解決方案。

  • 只要快要過期的時候刷新 jwt

一個上述方案的改造點(diǎn)是蜂怎,只在最后的幾分鐘返回給客戶端一個新的 jwt穆刻。這樣做,觸發(fā)刷新 jwt 基本就要看運(yùn)氣了杠步,如果用戶恰巧在最后幾分鐘訪問了服務(wù)器氢伟,觸發(fā)了刷新,萬事大吉幽歼;如果用戶連續(xù)操作了 27 分鐘朵锣,只有最后的 3 分鐘沒有操作,導(dǎo)致未刷新 jwt甸私,無疑會令用戶抓狂诚些。

  • 完善 refreshToken

借鑒 oauth2 的設(shè)計(jì),返回給客戶端一個 refreshToken颠蕴,允許客戶端主動刷新 jwt泣刹。一般而言,jwt 的過期時間可以設(shè)置為數(shù)小時犀被,而 refreshToken 的過期時間設(shè)置為數(shù)天椅您。

我認(rèn)為該方案并可行性是存在的,但是為了解決 jwt 的續(xù)簽把整個流程改變了寡键,為什么不考慮下 oauth2 的 password 模式和 client 模式呢掀泳?

  • 使用 redis 記錄獨(dú)立的過期時間
    那么和使用session存儲也沒有太多區(qū)別了

6. CSRF是什么

(Cross-site request forgery)跨站偽造請求。
攻擊者誘導(dǎo)受害者進(jìn)入第三方網(wǎng)站西轩,在第三方網(wǎng)站中员舵,向被攻擊網(wǎng)站發(fā)送跨站請求。利用受害者在被攻擊網(wǎng)站已經(jīng)獲取的注冊憑證藕畔,繞過后臺的用戶驗(yàn)證马僻,達(dá)到冒充用戶對被攻擊的網(wǎng)站執(zhí)行某項(xiàng)操作的目的
常見攻擊流程:

  • 受害者登錄a.com,并保留了登錄憑證(Cookie)注服。
  • 攻擊者引誘受害者訪問了b.com韭邓。
  • b.com向a.com發(fā)送了一個請求:a.com/act=xx措近。瀏覽器會默認(rèn)攜帶a.com的cookie
  • a.com接收到請求后,對請求進(jìn)行驗(yàn)證女淑,并確認(rèn)是受害者的憑證瞭郑,誤以為是受害者自己發(fā)送的請求。
  • a.com以受害者的名義執(zhí)行了act=xx鸭你。
  • 攻擊完成屈张,攻擊者在受害者不知情的情況下,冒充受害者袱巨,讓a.com執(zhí)行了自己定義的操作阁谆。
CSRF的特點(diǎn)
  • 攻擊一般發(fā)起在第三方網(wǎng)站,而不是被攻擊的網(wǎng)站瓣窄。被攻擊的網(wǎng)站無法防止攻擊發(fā)生笛厦。
  • 攻擊利用受害者在被攻擊網(wǎng)站的登錄憑證,冒充受害者提交操作俺夕;而不是直接竊取數(shù)據(jù)裳凸。
  • 整個過程攻擊者并不能獲取到受害者的登錄憑證,僅僅是“冒用”劝贸。
  • 跨站請求可以用各種方式:圖片URL姨谷、超鏈接、CORS映九、Form提交等等梦湘。部分請求方式可以直接嵌入在第三方論壇、文章中件甥,難以進(jìn)行追蹤捌议。

7. CSRF的解決方案

根據(jù)CSRF特點(diǎn)來處理,如果后端是restful服務(wù)引有,禁止跨域請求就可以杜絕絕大部分請求了瓣颅,然后可以再加上同源檢測(校驗(yàn)referer和origin)。
參考:如何防CSRF攻擊

8. Reference

JWT入門
理解JWT的使用場景和優(yōu)劣
如何防CSRF攻擊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末譬正,一起剝皮案震驚了整個濱河市宫补,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌曾我,老刑警劉巖粉怕,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抒巢,居然都是意外死亡贫贝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門蛉谜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稚晚,“玉大人凤优,你說我怎么就攤上這事◎诒耍” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵俺驶,是天一觀的道長幸逆。 經(jīng)常有香客問我,道長暮现,這世上最難降的妖魔是什么还绘? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮栖袋,結(jié)果婚禮上拍顷,老公的妹妹穿的比我還像新娘。我一直安慰自己塘幅,他們只是感情好昔案,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著电媳,像睡著了一般踏揣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匾乓,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天捞稿,我揣著相機(jī)與錄音,去河邊找鬼拼缝。 笑死娱局,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咧七。 我是一名探鬼主播衰齐,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猪叙!你這毒婦竟也來了娇斩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤穴翩,失蹤者是張志新(化名)和其女友劉穎犬第,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芒帕,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歉嗓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了背蟆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鉴分。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡哮幢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出志珍,到底是詐尸還是另有隱情橙垢,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布伦糯,位于F島的核電站柜某,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏敛纲。R本人自食惡果不足惜喂击,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淤翔。 院中可真熱鬧翰绊,春花似錦、人聲如沸旁壮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寡具。三九已至秤茅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間童叠,已是汗流浹背框喳。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厦坛,地道東北人五垮。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像杜秸,于是被迫代替她去往敵國和親放仗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345