前言
http是一個無狀態(tài)協(xié)議陵霉。什么是無狀態(tài)呢?就是說這一次請求和上一次請求是沒有任何關(guān)系的伍绳,互不認(rèn)識的踊挠,沒有關(guān)聯(lián)的。這種無狀態(tài)的的好處是快速冲杀。壞處是假如我們想要把www.zhihu.com/login.html和www.zhihu.com/index.html關(guān)聯(lián)起來止毕,必須使用某些手段和工具。
Cookie
Cookie是小甜餅的意思漠趁,主要有以下特點:
- 顧名思義扁凛,Cookie 確實非常小,它的大小限制為4KB左右
- 主要用途是保存登錄信息和標(biāo)記用戶(比如購物車)等闯传,不過隨著localStorage的出現(xiàn)谨朝,現(xiàn)在購物車的工作Cookie承擔(dān)的較少了
- 一般由服務(wù)器生成,可設(shè)置失效時間甥绿。如果在瀏覽器端生成Cookie字币,默認(rèn)是關(guān)閉瀏覽器后失效
- 每次都會攜帶在HTTP頭中,如果使用cookie保存過多數(shù)據(jù)會帶來性能問題
- 原生API不如storage友好共缕,需要自己封裝函數(shù)
API用法
服務(wù)端向客戶端發(fā)送的cookie(HTTP頭,不帶參數(shù)):
Set-Cookie: <cookie-name>=<cookie-value>
(name可選)
服務(wù)端向客戶端發(fā)送的cookie(HTTP頭洗出,帶參數(shù)):
Set-Cookie: <cookie-name>=<cookie-value>;(可選參數(shù)1);(可選參數(shù)2)
客戶端設(shè)置cookie:
document.cookie = "<cookie-name>=<cookie-value>;(可選參數(shù)1);(可選參數(shù)2)"
可選參數(shù):
Expires=<date>
:cookie的最長有效時間,若不設(shè)置則cookie生命期與會話期相同
Max-Age=<non-zero-digit>
:cookie生成后失效的秒數(shù)
Domain=<domain-value>
:指定cookie可以送達(dá)的主機域名图谷,若一級域名設(shè)置了則二級域名也能獲取翩活。
Path=<path-value>
:指定一個URL阱洪,例如指定path=/docs,則”/docs”菠镇、”/docs/Web/“冗荸、”/docs/Web/Http”均滿足匹配條件
Secure
:必須在請求使用SSL或HTTPS協(xié)議的時候cookie才回被發(fā)送到服務(wù)器
HttpOnly
:客戶端無法更改Cookie,客戶端設(shè)置cookie時不能使用這個參數(shù)利耍,一般是服務(wù)器端使用
示例:
Set-Cookie: sessionid=aes7a8; HttpOnly; Path=/
document.cookie = "KMKNKK=1234;Sercure"
可選前綴:
__Secure-
:以__Secure-
為前綴的cookie蚌本,必須與secure屬性一同設(shè)置,同時必須應(yīng)用于安全頁面(即使用HTTPS)
__Host-
:以__Host-
為前綴的cookie隘梨,必須與secure屬性一同設(shè)置程癌,同時必須應(yīng)用于安全頁面(即使用HTTPS)。必須不能設(shè)置domian屬性(這樣可以防止二級域名獲取一級域名的cookie)轴猎,path屬性的值必須為”/“嵌莉。
前綴使用示例:
Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
Set-Cookie: __Host-ID=123; Secure; Path=/
document.cookie = "__Secure-KMKNKK=1234;Sercure"
document.cookie = "__Host-KMKNKK=1234;Sercure;path=/"
Session
Session是在無狀態(tài)的HTTP協(xié)議下,服務(wù)端記錄用戶狀態(tài)時用于標(biāo)識具體用戶的機制税稼。它是在服務(wù)端保存的用來跟蹤用戶的狀態(tài)的數(shù)據(jù)結(jié)構(gòu),可以保存在文件垮斯、數(shù)據(jù)庫或者集群中郎仆。在瀏覽器關(guān)閉后這次的Session就消失了,下次打開不再擁有這個Session兜蠕。其實并不是Session消失了扰肌,而是Session ID變了,服務(wù)器端可能還是存著你上次的Session ID及其Session 信息熊杨,只是他們是無主狀態(tài)曙旭,也許一段時間后會被刪除。大多數(shù)的應(yīng)用都是用Cookie來實現(xiàn)Session跟蹤的晶府,第一次創(chuàng)建Session的時候桂躏,服務(wù)端會在HTTP協(xié)議中告訴客戶端,需要在Cookie里面記錄一個SessionID川陆,以后每次請求把這個會話ID發(fā)送到服務(wù)器
cookie和session的工作原理
由于http的無狀態(tài)性剂习,為了使某個域名下的所有網(wǎng)頁能夠共享某些數(shù)據(jù),session和cookie出現(xiàn)了较沪×廴疲客戶端訪問服務(wù)器的流程如下:
- 首先,客戶端會發(fā)送一個http請求到服務(wù)器端尸曼。
- 服務(wù)器端接受客戶端請求后们何,建立一個session,并發(fā)送一個http響應(yīng)到客戶端控轿,這個響應(yīng)頭冤竹,其中就包含Set-Cookie頭部拂封。該頭部包含了sessionId。Set-Cookie格式如下:
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
- 在客戶端發(fā)起的第二次請求贴见,假如服務(wù)器給了set-Cookie烘苹,瀏覽器會自動在請求頭中添加cookie
-
服務(wù)器接收請求,分解cookie片部,驗證信息镣衡,核對成功后返回response給客戶端
image.png
cookie和session的區(qū)別
-
Session
是在服務(wù)端保存的一個數(shù)據(jù)結(jié)構(gòu),用來跟蹤用戶的狀態(tài)档悠,這個數(shù)據(jù)可以保存在集群廊鸥、數(shù)據(jù)庫、文件中辖所,Cookie
是客戶端保存用戶信息的一種機制惰说,用來記錄用戶的一些信息,也是實現(xiàn)Session的一種方式缘回。 -
Cookie
的安全性
一般吆视,他人可通過分析存放在本地的Cookie
并進(jìn)行Cookie
欺騙。在安全性第一的前提下酥宴,選擇Session
更優(yōu)啦吧。重要交互信息比如權(quán)限等就要放在Session
中,一般的信息記錄放Cookie
就好了拙寡。 - 單個
Cookie
保存的數(shù)據(jù)不能超過4K授滓,很多瀏覽器都限制一個站點最多保存20個Cookie
。 - 當(dāng)訪問增多時肆糕,
Session
會較大地占用服務(wù)器的性能般堆。考慮到減輕服務(wù)器性能方面诚啃,應(yīng)當(dāng)適時使用Cookie
淮摔。 -
Session
的運行依賴Session ID
,而Session ID
是存在 Cookie 中的始赎。也就是說噩咪,如果瀏覽器禁用了Cookie
,Session
也會失效(但是可以通過其它方式實現(xiàn),比如在url
中傳遞Session ID
,即sid=xxxx)
注意:
- cookie只是實現(xiàn)session的其中一種方案极阅。雖然是最常用的胃碾,但并不是唯一的方法。禁用cookie后還有其他方法存儲筋搏,比如放在url中
- 現(xiàn)在大多都是Session + Cookie仆百,但是只用session不用cookie,或是只用cookie奔脐,不用session在理論上都可以保持會話狀態(tài)俄周∮跆郑可是實際中因為多種原因,一般不會單獨使用
用session只需要在客戶端保存一個id峦朗,實際上大量數(shù)據(jù)都是保存在服務(wù)端建丧。如果全部用cookie,數(shù)據(jù)量大的時候客戶端是沒有那么多空間的波势。 - 如果只用cookie不用session翎朱,那么賬戶信息全部保存在客戶端,一旦被劫持尺铣,全部信息都會泄露拴曲。并且客戶端數(shù)據(jù)量變大,網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量也會變大
- 簡而言之, session 有如用戶信息檔案表, 里面包含了用戶的認(rèn)證信息和登錄狀態(tài)等信息. 而 cookie 就是用戶通行證
token
token 也稱作令牌凛忿,由uid+time+sign[+固定參數(shù)]
token 的認(rèn)證方式類似于臨時的證書簽名, 并且是一種服務(wù)端無狀態(tài)的認(rèn)證方式, 非常適合于 REST API 的場景. 所謂無狀態(tài)就是服務(wù)端并不會保存身份認(rèn)證相關(guān)的數(shù)據(jù)澈灼。
組成
uid: 用戶唯一身份標(biāo)識
time: 當(dāng)前時間的時間戳
sign: 簽名, 使用 hash/encrypt 壓縮成定長的十六進(jìn)制字符串,以防止第三方惡意拼接
固定參數(shù)(可選): 將一些常用的固定參數(shù)加入到 token 中是為了避免重復(fù)查庫
存放
token在客戶端一般存放于localStorage店溢,cookie叁熔,或sessionStorage中。在服務(wù)器一般存于數(shù)據(jù)庫中
token認(rèn)證流程
token 的認(rèn)證流程與cookie很相似
- 用戶登錄床牧,成功后服務(wù)器返回Token給客戶端荣回。
- 客戶端收到數(shù)據(jù)后保存在客戶端
- 客戶端再次訪問服務(wù)器,將token放入headers中
- 服務(wù)器端采用filter過濾器校驗叠赦。校驗成功則返回請求數(shù)據(jù)驹马,校驗失敗則返回錯誤碼
token可以抵抗csrf革砸,cookie+session不行
假如用戶正在登陸銀行網(wǎng)頁除秀,同時登陸了攻擊者的網(wǎng)頁,且銀行網(wǎng)頁未對csrf攻擊進(jìn)行防護(hù)算利。攻擊者可以在網(wǎng)頁放一個表單册踩,該表單提交src為http://www.bank.com/api/transfer,body為count=1000&to=Tom效拭。倘若是session+cookie暂吉,用戶打開網(wǎng)頁的時候就已經(jīng)轉(zhuǎn)給Tom1000元了。因為form 發(fā)起的 POST 請求并不受到瀏覽器同源策略的限制缎患,因此可以任意地使用其他域的 Cookie 向其他域發(fā)送 POST 請求慕的,形成 CSRF 攻擊。在post請求的瞬間挤渔,cookie會被瀏覽器自動添加到請求頭中肮街。但token不同,token是開發(fā)者為了防范csrf而特別設(shè)計的令牌判导,瀏覽器不會自動添加到headers里嫉父,攻擊者也無法訪問用戶的token沛硅,所以提交的表單無法通過服務(wù)器過濾,也就無法形成攻擊绕辖。
localStorage和sessionStorage
兩者的共同點:
- 存儲大小均為5M左右
- 都有同源策略限制
- 僅在客戶端中保存摇肌,不參與和服務(wù)器的通信
兩者的不同點:
1、生命周期
—— 數(shù)據(jù)可以存儲多少時間
- localStorage: 存儲的數(shù)據(jù)是永久性的仪际,除非用戶人為刪除否則會一直存在围小。
- sessionStorage: 與存儲數(shù)據(jù)的腳本所在的標(biāo)簽頁的有效期是相同的。一旦窗口或者標(biāo)簽頁被關(guān)閉弟头,那么所有通過 sessionStorage 存儲的數(shù)據(jù)也會被刪除吩抓。
2、作用域
—— 誰擁有數(shù)據(jù)的訪問權(quán) - localStorage: 在同一個瀏覽器內(nèi)赴恨,
同源文檔
之間共享 localStorage 數(shù)據(jù)疹娶,可以互相讀取、覆蓋伦连。 - sessionStorage: 與 localStorage 一樣需要同一瀏覽器同源文檔這一條件雨饺。不僅如此,sessionStorage 的作用域還被限定在了窗口中惑淳,也就是說额港,只有同一瀏覽器、同一窗口的同源文檔才能共享數(shù)據(jù)歧焦。
為了更好的理解sessionStorage
,我們來看個例子:
例如你在瀏覽器中打開了兩個相同地址的頁面A移斩、B,雖然這兩個頁面的源完全相同,但是他們還是不能共享數(shù)據(jù)绢馍,因為他們是不同窗口中的向瓷。但是如果是一個窗口中,有兩個同源的iframe
元素的話舰涌,這兩個iframe
的 sessionStorage 是可以互通的猖任。
API
//sessionStorage用法相同
localStorage.setItem("name",1); // 以"x"為名字存儲一個數(shù)值
localStorage.getItem("name"); // 獲取數(shù)值
localStorage.key(i); // 獲取第i對的名字
localStorage.removeItem("name"); // 獲取該對的值
localStorage.clear(); // 全部刪除