網(wǎng)絡(luò)面經(jīng):你真的了解Cookie和Session嗎?
在初級面試中,關(guān)于Cookie和Session的區(qū)別是一個(gè)高頻的面試題。如果只是機(jī)械的回答一下它們的區(qū)別,那你可能真的不了解Cookie和Session,就更別說靈活運(yùn)用了。
這篇文章帶你從Cookie和Session的初級應(yīng)用到高級應(yīng)用捋一遍,看看有多少不知道的內(nèi)容。
什么是Cookie?
我們知道HTTP協(xié)議是無狀態(tài)的,一次請求完成,不會持久化請求與相應(yīng)的信息。那么,在購物車、用戶登錄狀態(tài)、頁面?zhèn)€性化設(shè)置等場景下,就無法識別特定用戶的信息。這時(shí)Cookie就出現(xiàn)了。
Cookie是客戶端保存用戶信息的一種機(jī)制,將服務(wù)器發(fā)送到瀏覽器的數(shù)據(jù)保存在本地,下次向同一服務(wù)器再發(fā)起請求時(shí)被攜帶發(fā)送。對于Cookie,可以設(shè)置過期時(shí)間。
通常,Cookie用于告知服務(wù)端兩個(gè)請求是否來自同一瀏覽器,如保持用戶的登錄狀態(tài)。這樣就解決了HTTP無狀態(tài)的問題。
Cookie主要用于以下方面:
- 會話狀態(tài)管理(如用戶登錄狀態(tài)、購物車、游戲分?jǐn)?shù)或其它需要記錄的信息)
- 個(gè)性化設(shè)置(如用戶自定義設(shè)置、主題等)
- 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)
Cookie存儲在客戶端,這就意味著,可以通過一些方式進(jìn)行修改,欺騙服務(wù)器。針對這個(gè)問題,怎么解決呢?那就引入了Session。
什么是Session?
Session代表服務(wù)器和客戶端一次會話的過程。
維基百科這樣解釋道:在計(jì)算機(jī)科學(xué)領(lǐng)域來說,尤其是在網(wǎng)絡(luò)領(lǐng)域,會話(session)是一種持久網(wǎng)絡(luò)協(xié)議,在用戶(或用戶代理)端和服務(wù)器端之間創(chuàng)建關(guān)聯(lián),從而起到交換數(shù)據(jù)包的作用機(jī)制,session在網(wǎng)絡(luò)協(xié)議(例如telnet或FTP)中是非常重要的部分。
對照Cookie,Session是一種在服務(wù)器端保存數(shù)據(jù)的機(jī)制,用來跟蹤用戶狀態(tài)的數(shù)據(jù)結(jié)構(gòu),可以保存在文件、數(shù)據(jù)庫或者集群中。
當(dāng)在應(yīng)用程序的Web頁之間跳轉(zhuǎn)時(shí),存儲在Session對象中的變量將不會丟失,而會在整個(gè)用戶會話中一直存在下去。當(dāng)客戶端關(guān)閉會話,或者Session超時(shí)失效時(shí)會話結(jié)束。
目前大多數(shù)的應(yīng)用都是用Cookie實(shí)現(xiàn)Session跟蹤的。第一次創(chuàng)建Session時(shí),服務(wù)端會通過在HTTP協(xié)議中返回給客戶端,在Cookie中記錄SessionID,后續(xù)請求時(shí)傳遞SessionID給服務(wù),以便后續(xù)每次請求時(shí)都可分辨你是誰。
Cookie與Session的區(qū)別
關(guān)于Cookie與Session的區(qū)別,就是在面試中經(jīng)?;卮鸬膯栴}了。
- 作用范圍不同,Cookie 保存在客戶端(瀏覽器),Session 保存在服務(wù)器端。
- 存取方式的不同,Cookie只能保存 ASCII,Session可以存任意數(shù)據(jù)類型,比如UserId等。
- 有效期不同,Cookie可設(shè)置為長時(shí)間保持,比如默認(rèn)登錄功能功能,Session一般有效時(shí)間較短,客戶端關(guān)閉或者Session超時(shí)都會失效。
- 隱私策略不同,Cookie存儲在客戶端,信息容易被竊取;Session存儲在服務(wù)端,相對安全一些。
- 存儲大小不同, 單個(gè)Cookie 保存的數(shù)據(jù)不能超過 4K,Session可存儲數(shù)據(jù)遠(yuǎn)高于Cookie。
禁用Cookie會怎樣?
如果客戶在瀏覽器禁用了Cookie,該怎么辦呢?
方案一:拼接SessionId參數(shù)。在GET或POST請求中拼接SessionID,GET請求通常通過URL后面拼接參數(shù)來實(shí)現(xiàn),POST請求可以放在Body中。無論哪種形式都需要與服務(wù)器獲取保持一致。
這種方案比較常見,比如老外的網(wǎng)站,經(jīng)常會提示是否開啟Cookie。如果未點(diǎn)同意或授權(quán),會發(fā)現(xiàn)瀏覽器的URL路徑中往往有"?sessionId=123abc"這樣的參數(shù)。
方案二:基于Token(令牌)。在APP應(yīng)用中經(jīng)常會用到Token來與服務(wù)器進(jìn)行交互。Token本質(zhì)上就是一個(gè)唯一的字符串,登錄成功后由服務(wù)器返回,標(biāo)識客戶的臨時(shí)授權(quán),客戶端對其進(jìn)行存儲,在后續(xù)請求時(shí),通常會將其放在HTTP的Header中傳遞給服務(wù)器,用于服務(wù)器驗(yàn)證請求用戶的身份。
分布式系統(tǒng)中Session如何處理?
在分布式系統(tǒng)中,往往會有多臺服務(wù)器來處理同一業(yè)務(wù)。如果用戶在A服務(wù)器登錄,Session位于A服務(wù)器,那么當(dāng)下次請求被分配到B服務(wù)器,將會出現(xiàn)登錄失效的問題。
針對類似的場景,有三種解決方案:
方案一:請求精確定位。也就是通過負(fù)載均衡器讓來自同一IP的用戶請求始終分配到同一服務(wù)上。比如,Nginx的ip_hash策略,就可以做到。
方案二:Session復(fù)制共享。該方案的目標(biāo)就是確保所有的服務(wù)器的Session是一致的。像Tomcat等多數(shù)主流web服務(wù)器都采用了Session復(fù)制實(shí)現(xiàn)Session的共享.
方案三:基于共享緩存。該方案是通過將Session放在一個(gè)公共地方,各個(gè)服務(wù)器使用時(shí)去取即可。比如,存放在Redis、Memcached等緩存中間件中。
在Spring Boot項(xiàng)目中,如果集成了Redis,Session共享可以非常方便的實(shí)現(xiàn)。
同源策略與跨域請求
所謂的“同源”指的是“三個(gè)相同”:協(xié)議相同、域名相同、端口相同。只有這三個(gè)完全相同,才算是同源。
同源策略的目的:是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
比如,用戶訪問了銀行網(wǎng)站A,再去瀏覽其他網(wǎng)站,如果其他網(wǎng)站可以讀取A的Cookie,隱私信息便會泄露。更可怕的是,通常Cookie還用來保存用戶登錄狀態(tài),會出現(xiàn)冒充用戶行為。因此,"同源策略"是必需的,如果Cookie可以共享,互聯(lián)網(wǎng)就毫無安全可言了。
同源策略保證了一定的安全性,但在某些場景下也帶來了不便,比如常見的跨域請求問題。
在HTML中,<a>,<form>, <img>, <script>, <iframe>, <link> 等標(biāo)簽以及Ajax都可以指向一個(gè)資源地址,而所謂的跨域請求就是指:當(dāng)前發(fā)起請求的域與該請求指向的資源所在的域不一樣。同源即同域,三項(xiàng)有一項(xiàng)不同便會出現(xiàn)跨域請求。
瀏覽器會對跨域請求做出限制,因?yàn)榭缬蛘埱罂赡軙焕冒l(fā)動CSRF攻擊。
CSRF(Cross-site request forgery),即“跨站請求偽造”,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。CSRF攻擊者在用戶已經(jīng)登錄目標(biāo)網(wǎng)站之后,誘使用戶訪問一個(gè)攻擊頁面,利用目標(biāo)網(wǎng)站對用戶的信任,以用戶身份在攻擊頁面對目標(biāo)網(wǎng)站發(fā)起偽造用戶操作的請求,達(dá)到攻擊目的。
針對跨域請求通常有如下方法:
- 通過代理避開跨域請求;
- 通過Jsonp跨域;
- 通過跨域資源共享(CORS);
關(guān)于跨域的具體解決步驟,就不再展開了。
小結(jié)
在準(zhǔn)備面試題時(shí),我們通常只會去背誦Cookie和Session的區(qū)別。但只有系統(tǒng)的學(xué)習(xí)才能更深刻的把知識點(diǎn)串聯(lián)起來,形成強(qiáng)大記憶,融會貫通的效果。比如,本文了解了Cookie與Session出現(xiàn)的原因、解決的問題以及引入之后又會帶來什么問題等,更加系統(tǒng)全面的掌握了這一知識點(diǎn)。