1.cookie
在前端請(qǐng)求網(wǎng)絡(luò)資源或是后端接口時(shí),請(qǐng)求頭 Headers 里都會(huì)帶上當(dāng)前域下的 cookie 信息,服務(wù)端通過檢測(cè)請(qǐng)求頭內(nèi)的 cookie 判斷當(dāng)前用戶的登錄狀態(tài)是否過期,或是 cookie 是否錯(cuò)誤,來判斷當(dāng)前用戶是否能成功返回響應(yīng)。這個(gè)過程大概是,前端請(qǐng)求登錄接口,后端驗(yàn)證用戶名和密碼是否正確。在正確的情況下服務(wù)端 Set-Cookie ,參數(shù)大致是域名、有效時(shí)間、secure (是否 HTTPS ) 等,種下 cookie 之后,瀏覽器就會(huì)在指定域下添加相應(yīng)的 cookie 信息
2.session
session 是另一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制。session存儲(chǔ)在服務(wù)器端,該會(huì)話對(duì)應(yīng)的key即sessionId會(huì)被存儲(chǔ)到客戶端的cookie中。
Cookie 和 Session 對(duì)比
安全性: Session 比 Cookie 安全,Session 是存儲(chǔ)在服務(wù)器端的,Cookie 是存儲(chǔ)在客戶端的。
存取值的類型:Cookie只支持存字符串?dāng)?shù)據(jù),想要設(shè)置其他類型的數(shù)據(jù),需要將其轉(zhuǎn)換成字符串,Session 可以存任意數(shù)據(jù)類型。
有效期: Cookie可設(shè)置為長(zhǎng)時(shí)間保持,比如我們經(jīng)常使用的默認(rèn)登錄功能,Session 一般失效時(shí)間較短,客戶端關(guān)閉(默認(rèn)情況下)或者 Session 超時(shí)都會(huì)失效。
存儲(chǔ)大小: 單個(gè) Cookie 保存的數(shù)據(jù)不能超過 4K,Session 可存儲(chǔ)數(shù)據(jù)遠(yuǎn)高于 Cookie,但是當(dāng)訪問量過多,會(huì)占用過多的服務(wù)器資源。
session缺點(diǎn):
占資源: 每個(gè)經(jīng)過認(rèn)證的用戶都要存放session到內(nèi)存中,而隨著認(rèn)證用戶的增多,服務(wù)端的開銷較大。
CSRF攻擊:基于cookie來進(jìn)行用戶識(shí)別時(shí),用戶cookie如果被截獲,就容易受到跨站請(qǐng)求偽造的攻擊。
3.token
Token 是服務(wù)器生成的一串隨機(jī)字符串或者一個(gè) json 串,用于客戶端進(jìn)行資源請(qǐng)求的令牌。當(dāng)我們調(diào)用登錄接口之后,服務(wù)端返回給前端一個(gè) Token ,之后存儲(chǔ) Token 到本地環(huán)境,每次前端請(qǐng)求接口的時(shí)候,都需要在請(qǐng)求頭里帶上 Token 信息,并且 Token 可以在服務(wù)端設(shè)置過期時(shí)間。Token 過期之后,前端在請(qǐng)求失敗回調(diào) 406(前后端協(xié)商好錯(cuò)誤碼)之后重新跳轉(zhuǎn)到登錄界面進(jìn)行鑒權(quán)。
Token 和 Session 的區(qū)別
Session 是一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制,使服務(wù)端有狀態(tài)化,可以記錄會(huì)話信息。而 Token 是令牌,訪問資源接口(API)時(shí)所需要的資源憑證。Token 使服務(wù)端無狀態(tài)化,不會(huì)存儲(chǔ)會(huì)話信息。Session 和 Token 并不矛盾,作為身份認(rèn)證 Token 安全性比 Session 好,因?yàn)槊恳粋€(gè)請(qǐng)求都有簽名還能防止監(jiān)聽以及重放攻擊,而 Session 就必須依賴鏈路層來保障通訊安全了。如果你需要實(shí)現(xiàn)有狀態(tài)的會(huì)話,仍然可以增加 Session 來在服務(wù)器端保存一些狀態(tài)。
所謂 Session 認(rèn)證只是簡(jiǎn)單的把 User 信息存儲(chǔ)到 Session 里,因?yàn)?SessionID 的不可預(yù)測(cè)性,暫且認(rèn)為是安全的。而 Token ,如果指的是 OAuth Token 或類似的機(jī)制的話,提供的是 認(rèn)證 和 授權(quán) ,認(rèn)證是針對(duì)用戶,授權(quán)是針對(duì) App 。其目的是讓某 App 有權(quán)利訪問某用戶的信息。
4.JWT
JSON Web Token(簡(jiǎn)稱JWT)是目前最流行的跨域認(rèn)證解決方案,是一種認(rèn)證授權(quán)機(jī)制,是一種基于 JSON 的開放標(biāo)準(zhǔn)。
JWT 認(rèn)證流程:
用戶輸入用戶名/密碼登錄,服務(wù)端認(rèn)證成功后,會(huì)返回給客戶端一個(gè) JWT。
客戶端將 jwt 保存到本地,當(dāng)用戶希望訪問一個(gè)受保護(hù)的路由或者資源的時(shí)候,需要請(qǐng)求頭的 Authorization 字段中使用 Bearer 模式添加 JWT 。
服務(wù)端的保護(hù)路由將會(huì)檢查請(qǐng)求頭 Authorization 中的 JWT 信息,如果合法,則允許訪問。因?yàn)?JWT 內(nèi)部包含了一些用戶信息,因此減少了需要查詢數(shù)據(jù)庫(kù)的需要。
JWT 的使用方式
1、存放在cookie中
當(dāng)用戶希望訪問一個(gè)受保護(hù)的路由或者資源的時(shí)候,可以把它放在 Cookie 里面自動(dòng)發(fā)送,但是這樣不能跨域。
2、存放在localstorage中,添加到header中發(fā)送
請(qǐng)求時(shí)放在 HTTP 請(qǐng)求頭信息的 Authorization 字段里,使用 Bearer 模式添加 JWT。
Authorization: Bearer <token>
3、通過接口參數(shù)
可以把 JWT 放在 POST 請(qǐng)求的數(shù)據(jù)體里,或者通過 URL 的 queryString 傳輸。
自定義Token 和 JWT 的關(guān)系
相同點(diǎn): 都是訪問資源的令牌,都可以記錄用戶的信息,都是使服務(wù)端無狀態(tài)化,都是只有驗(yàn)證成功后,客戶端才能訪問服務(wù)端上受保護(hù)的資源
區(qū)別:服務(wù)端驗(yàn)證客戶端發(fā)來的token信息要進(jìn)行數(shù)據(jù)的查詢操作;JWT驗(yàn)證客戶端發(fā)來的token信息就不用, 在服務(wù)端使用密鑰校驗(yàn)就可以,不用數(shù)據(jù)庫(kù)的查詢。
使用 cookie 注意點(diǎn)
? 因?yàn)榇鎯?chǔ)在客戶端,容易被客戶端篡改,使用前需要驗(yàn)證合法性
? 不要存儲(chǔ)敏感數(shù)據(jù),比如用戶密碼,賬戶余額
? 使用 httpOnly 在一定程度上提高安全性
? 盡量減少 cookie 的體積,能存儲(chǔ)的數(shù)據(jù)量不能超過 4kb
? 設(shè)置正確的 domain 和 path,減少數(shù)據(jù)傳輸
? cookie 無法跨域,子域名可以訪問父域名
? 一個(gè)瀏覽器針對(duì)一個(gè)網(wǎng)站最多存 20 個(gè)Cookie,瀏覽器一般只允許存放 300 個(gè)Cookie
? 移動(dòng)端對(duì) cookie 的支持不是很好,而 session 一般基于 cookie 實(shí)現(xiàn),所以移動(dòng)端常用的是 token
使用 session 注意點(diǎn)
? 用戶同時(shí)在線量較多時(shí),session 存儲(chǔ)在服務(wù)器會(huì)占據(jù)較多內(nèi)存,需要定期清理過期 的 session
? 當(dāng)網(wǎng)站采用集群部署的時(shí)候,會(huì)遇到多臺(tái) web 服務(wù)器之間如何做 session 共享的問題。因?yàn)?session是由單個(gè)服務(wù)器創(chuàng)建的,處理用戶請(qǐng)求的服務(wù)器不一定是 那個(gè)創(chuàng)建 session 的服務(wù)器,那么該服務(wù)器就無法拿到之前已經(jīng)放入到 session 中的登錄憑證之類的信息了。
? 當(dāng)多個(gè)應(yīng)用要共享 session時(shí),因?yàn)椴煌膽?yīng)用可能部署的主機(jī)不一樣需要在各個(gè)應(yīng)用做好 cookie 跨域的處理。
? sessionId 是存儲(chǔ)在 cookie 中的,假如瀏覽器禁止 cookie 或不支持 cookie ,一般會(huì)把 sessionId 跟在 url 參數(shù)后面即重寫 url,所以 session 不一定非得需要靠 cookie 實(shí)現(xiàn)
使用 token 注意點(diǎn)
? 如果你認(rèn)為用數(shù)據(jù)庫(kù)來存儲(chǔ) token會(huì)導(dǎo)致查詢時(shí)間太長(zhǎng),可以選擇放在 內(nèi)存當(dāng)中,比如 redis 很適合你對(duì) token 查詢的需求。
? token 完全由應(yīng)用管理,所以它可以避開同源策略
? token 可以避免 CSRF 攻擊(因?yàn)椴恍枰?cookie 了)
? 移動(dòng)端對(duì) cookie 的支持不是很好,而 session 需要基于 cookie 實(shí)現(xiàn),所以移動(dòng)端常用的是 token
使用 JWT 時(shí)需要考慮的問題
? JWT 默認(rèn)是不加密,但也是可以加密的。生成原始 Token 以后,可以用密鑰再加密一次。
? JWT 不加密的情況下,不能將秘密數(shù)據(jù)寫入 JWT。
? JWT 不僅可以用于認(rèn)證,也可以用于交換信息。有效使用 JWT,可以降低服務(wù)器查詢數(shù)據(jù)庫(kù)的次數(shù)。
? JWT 最大的優(yōu)勢(shì)是服務(wù)器不再需要存儲(chǔ)Session,使得服務(wù)器認(rèn)證鑒權(quán)業(yè)務(wù)可以方便擴(kuò)展。但這也是 JWT 最大的缺點(diǎn):由于服務(wù)器不需要存儲(chǔ) Session 狀態(tài),因此使用過程中無法廢棄某個(gè) Token 或者更改 Token 的權(quán)限。也就是說一旦 JWT 簽發(fā)了,到期之前就會(huì)始終有效,除非服務(wù)器部署額外的邏輯。
? JWT 本身包含了認(rèn)證信息,一旦泄露,任何人都可以獲得該令牌的所有權(quán)限。為了減少盜用,JWT的有效期應(yīng)該設(shè)置得比較短。對(duì)于一些比較重要的權(quán)限,使用時(shí)應(yīng)該再次對(duì)用戶進(jìn)行認(rèn)證。
? JWT 適合一次性的命令認(rèn)證,頒發(fā)一個(gè)有效期極短的JWT,即使暴露了危險(xiǎn)也很小由 于每次操作都會(huì)生成新的 JWT,因此也沒必要保存 JWT,真正實(shí)現(xiàn)無狀態(tài)。
? 為了減少盜用,JWT 不應(yīng)該使用 HTTP 協(xié)議明碼傳輸,要使用 HTTPS 協(xié)議傳輸。