前記:前段時間搞一個活動,開發的時間被嚴重壓縮,忙到飛起,以至於都沒怎麼寫文章了,內疚.javascript
2月份參加了一場面試,有一些關於cookie的問題回答的不是很好,因此這篇文章咱們來對cooKie作一個探討和總結,查漏補缺。其實本文很早以前都寫的差很少了,不過關於cookie跨域方面,查了比較多的資料,始終沒有一個太好的結果,因此本文一直沒有發佈。html
本文的不少內容都是參考網上的資料,能夠說是好幾篇資料的集合,畢竟是總結嘛,就是將本身以爲有用的東西集合在一塊兒。前端
官方定義:Netscape官方文檔中的定義爲,Cookie是指在HTTP協議下,服務器或腳本能夠維護客戶端計算機上信息的一種方式 。通俗地說,Cookie是一種可以讓網站Web服務器把少許數據儲存到客戶端的硬盤或內存裏,或是從客戶端的硬盤裏讀取數據的一種技術。 Cookie文件則是指在瀏覽某個網站時,由Web服務器的CGI腳本建立的存儲在瀏覽器客戶端計算機上的一個小文本文件,其格式爲:用戶名@網站地址 [數字].txt。java
再通俗一點的講,因爲HTTP是一種無狀態的協議,服務器單從網絡鏈接上無從知道客戶身份。怎麼辦呢?就給客戶端們頒發一個通行證,每人一個,不管誰訪問都必須攜帶本身通行證。這樣服務器就能從通行證上確認客戶身份了。node
HTTP協議是一種無狀態、無鏈接的協議,不能在服務器上保持一次會話的連續狀態信息。Cookie的做用是記錄用戶的有關信息,它最根本的用途是幫助Web站點保存有關訪問者的信息。如身份識別號碼ID、密碼、瀏覽過的網頁、停留的時間、用戶在Web站點購物的方式或用戶訪問該站點的次數等,當用戶再次連接Web服務器時,瀏覽器讀取Cookie信息並傳遞給Web站點。 nginx
咱們先來看一張圖:面試
在谷歌瀏覽器開發者模式中,咱們能夠看到網站的cookie,因此,相應的,咱們就能夠知道cookie的一些屬性了,接下來介紹Cookie中的一些屬性數據庫
如圖所示,cookie具備的屬性有 Name、value、Domain、path、Expires/Max-Age、Size、HTTP、Secure等等,咱們接下來詳細瞭解瞭解json
Name:後端
該Cookie的名稱,一旦建立,名稱便不可更改
value:
該Cookie的值,若是值爲Unicode字符,須要爲字符編碼,若是值爲二進制數據,則須要使用BASE64編碼
domain:
能夠訪問該Cookie的域名。若是設置爲」.google.com」,則全部以」google.com」結尾的域名均可以訪問該Cookie。注意第一個字符必須爲「.」
這個domain稍做解釋:
非頂級域名,如二級域名或者三級域名,設置的cookie的domain只能爲頂級域名或者二級域名或者三級域名自己,不能設置其餘二級域名的cookie,不然cookie沒法生成。
頂級域名只能設置domain爲頂級域名,不能設置爲二級域名或者三級域名,不然cookie沒法生成。
二級域名能讀取設置了domain爲頂級域名或者自身的cookie,不能讀取其餘二級域名domain的cookie。因此要想cookie在多個二級域名中共享,須要設置domain爲頂級域名,這樣就能夠在全部二級域名裏面或者到這個cookie的值了。
頂級域名只能獲取到domain設置爲頂級域名的cookie,其餘domain設置爲二級域名的沒法獲取。
Path:
path字段爲能夠訪問此cookie的頁面路徑。 好比domain是abc.com, path是/detail,那麼只有/detail 路徑下的頁面能夠讀取此cookie。
Expires/Max-Age:
該Cookie失效時間,單位秒。若是爲正數,則Cookie在maxAge秒以後失效。
若是爲負數,該Cookie爲臨時Cookie,關閉瀏覽器即失效,瀏覽器也不會以任何形式保存Cookie.
若是爲0,表示刪除Cookie。默認是-1
Size:
cookie的大小
http:
cookie的httponly屬性。若此屬性爲true,則只有在http請求頭中會帶有此cookie的信息,而不能經過document.cookie來訪問此cookie。
好比截圖中的__jsluid
secure:
設置是否只能經過https來傳遞此條cookie
一、一個瀏覽器針對一個網站最多存20個Cookie,瀏覽器通常只容許存放300個Cookie
二、每一個Cookie的長度不能超過4KB(稀缺)。但不一樣的瀏覽器實現的不一樣
三、Cookie的不可跨域名性。
例如:Cookie在客戶端是由瀏覽器來管理的,瀏覽器可以保證Google只會操做Google的Cookie而不會操做Baidu的Cookie,從而保證用戶的隱私安全。
cookie有兩種類型:
不設置過時時間,則表示這個cookie生命週期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期爲瀏覽會話期的cookie被稱爲會話cookie。會話cookie通常不保存在硬盤上而是保存在內存裏。能夠類比於本地存儲的sessionstore
設置了過時時間,瀏覽器就會把cookie保存到硬盤上,關閉後再次打開瀏覽器,這些cookie依然有效直到超過設定的過時時間。
存儲在硬盤上的cookie能夠在不一樣的瀏覽器進程間共享,好比兩個IE窗口。而對於保存在內存的cookie,不一樣的瀏覽器有不一樣的處理方式。能夠類比於本地存儲的localstore
服務器端像客戶端發送Cookie是經過HTTP響應報文實現的,在Set-Cookie中設置須要像客戶端發送的cookie,cookie格式以下:
Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"
其中name=value是必選項,其它都是可選項。
客戶端的話用js便可操做,因爲如今客戶端設置大部分用H5的本地存儲localstore和sessionstore多一點,因此客戶端的這裏不作介紹
這裏介紹的js來讀取cookie,能夠直接使用下面的方法,其實就是用document.cookie:
function getCookie(name){ var cookieName=encodeURIComponent(name)+"=", cookieStart=document.cookie.indexOf(cookieName), cookieValue=null; if(cookieStart>-1){ var cookieEnd=document.cookie.indexOf(";",cookieStart); if(cookieEnd==-1){ cookieEnd=document.cookie.Length; } cookieValue=decodeURIComponent(document.cookie.substring(cookieStart+document.cookie.length,cookieEnd)); } return cookieValue; }
Cookie並不提供修改、刪除操做。若是要修改某個Cookie,只須要新建一個同名的Cookie,添加到response中覆蓋原來的Cookie。
若是要刪除某個Cookie,只須要新建一個同名的Cookie,並將maxAge設置爲0,並添加到response中覆蓋原來的Cookie。注意是0而不是負數。
Cookie其實是一小段的文本信息。客戶端請求服務器,若是服務器須要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。服務器還能夠根據須要修改Cookie的內容。以下圖所示:
這個跟其實跟瀏覽器你器緩存有點相似,具體的過程咱們能夠分解分解:
(1)客戶端在瀏覽器的地址欄中鍵入Web服務器的URL,瀏覽器發送讀取網頁的請求。
(2)服務器接收到請求後,產生一個Set-Cookie報頭,放在HTTP報文中一塊兒回傳客戶端,發起一次會話。
(3)客戶端收到應答後,若要繼續該次會話,則將Set-Cook-ie中的內容取出,造成一個Cookie.txt文件儲存在客戶端計算機裏。
(4)當客戶端再次向服務器發出請求時,瀏覽器先在電腦裏尋找對應該網站的Cookie.txt文件。若是找到,則根據此Cookie.txt產生Cookie報頭,放在HTTP請求報文中發給服務器。
(5)服務器接收到包含Cookie報頭的請求,檢索其Cookie中與用戶有關的信息,生成一個客戶端所請示的頁面應答傳遞給客戶端。 瀏覽器的每一次網頁請求,均可以傳遞已存在的Cookie文件,例如,瀏覽器的打開或刷新網頁操做。
一般cookie信息都是使用http鏈接傳遞數據,這種傳遞方式很容易被查看,並且js裏面直接有一個document.cookie方法,能夠直接獲取到用戶的cooie,因此cookie存儲的信息容易被竊取。假如cookie中所傳遞的內容比較重要,那麼就要求使用加密的數據傳輸。
如何來防範cookie的安全呢?有如下幾種方法:
(1)HttpOnly屬性
若是在Cookie中設置了"HttpOnly"屬性,那麼經過程序(JS腳本、Applet等)將沒法讀取到Cookie信息,這樣能有效的防止XSS攻擊。
(2)secure屬性
當設置爲true時,表示建立的 Cookie 會被以安全的形式向服務器傳輸,也就是隻能在 HTTPS 鏈接中被瀏覽器傳遞到服務器端進行會話驗證,若是是 HTTP 鏈接則不會傳遞該信息,因此不會被盜取到Cookie 的具體內容。
咱們再來看看一道經典的面試題:
登陸時候用cookie的話,安全性問題怎麼解決?
這個問題,網上找了比較久的答案,比較滿意的有兩種答案(答案是網上找的)
第一種是:
把用戶對象(包含了用戶ID、用戶名、是否登陸..)序列化成字符串再加密存入Cookie。
密鑰是:客戶端IP+瀏覽器Agent+用戶標識+固定的私有密鑰
當cookie被竊取後,只要任一信息不匹配,就沒法解密cookie,進而也就不能登陸了。
這樣作的缺點是IP不能變更、頻繁加密解密會加劇CPU負擔
第二種是:
將用戶的認證信息保存在一個cookie中,具體以下:
1.cookie名:uid。推薦進行加密,好比MD5(‘站點名稱’)等。
2.cookie值:登陸名|有效時間Expires|hash值。hash值能夠由」登陸名+有效時間Expires+用戶密碼(加密後的)的前幾位 +salt」 (salt是保證在服務器端站點配置文件中的隨機數)
這樣子設計有如下幾個優勢:
1.即便數據庫被盜了,盜用者仍是沒法登陸到系統,由於組成cookie值的salt是保證在服務器站點配置文件中而非數據 庫。
2.若是帳戶被盜了,用戶修改密碼,可使盜用者的cookie值無效。
3.若是服務器端的數據庫被盜了,經過修改salt值可使全部用戶的cookie值無效,迫使用戶從新登陸系統。
4.有效時間Expires能夠設置爲當前時間+過去時間(好比2天),這樣能夠保證每次登陸的cookie值都不同,防止盜用者 窺探到本身的cookie值後做爲後門,長期登陸。
cookie是不能跨域訪問的,那麼,假如須要跨域來進行cookie的訪問和傳遞,該怎麼辦呢?查找了比較多的資料,比較少這方面的資料,
在cookie跨域這個問題上,前端能作的很少,不少都是須要和後端一塊兒配合來完成。
總結了下面的幾種方法,具體的實現過程這裏沒有寫,能夠點擊我提供的連接本身看看。
前2種具體的實現方法能夠點擊看這裏:點我
一、nginx方向代理:
反向代理(Reverse Proxy)方式是指以代理服務器來接受Internet上的鏈接請求,而後將請求轉發給內部網絡上的服務器;並將從服務器上獲得的結果返回給Internet上請求鏈接的客戶端,此時代理服務器對外就表現爲一個服務器。
反向代理服務器對於客戶端而言它就像是原始服務器,而且客戶端不須要進行任何特別的設置。客戶端向反向代理 的命名空間(name-space)中的內容發送普通請求,接着反向代理將判斷向何處(原始服務器)轉交請求,並將得到的內容返回給客戶端,就像這些內容 本來就是它本身的同樣。
二、jsonp方法:
這個方法和咱們平時處理js跨域的jsonp方法同樣。具體實現方法能夠看看淘寶的解決方法,點我
三、nodejs的superagent
四、iframe方法:
好比有個www.a.com/index.html的頁面,往www.b.com/index.html的頁面傳遞cookie
www.a.com/index.html這樣寫:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>我是a頁面</title> </head> <body> </body> <script type="text/javascript"> document.cookie = "name=" + "value;" + "expires=" + "datatime;" + "domain=" + "" + "path=" + "/path" + "; secure"; //name Cookie名字 //value Cookie值 //expires 有效期截至(單位毫秒) //path 子目錄 //domain 有效域 //secure 是否安全 window.location = "http://www.b.com/index.html?" + document.cookie; //跳轉到b頁面 </script> </html>
www.b.com/index.html 這樣寫:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>我是b頁面</title> </head> <body> <iframe src='http://www.a.com/index.html' width='100' height='100' style="display:none"></iframe> </body> <script type="text/javascript"> var url = window.location.toString();//獲取地址 var get = url.substring(url.indexOf("abc"));//獲取變量和變量值 var idx = get.indexOf("=");//獲取變量名長度 if (idx != -1) { var name = get.substring(0, idx);//獲取變量名 var val = get.substring(idx + 1);//獲取變量值 setCookie(name, val, 1);//建立Cookie } </script> </html>
備註:本文主要是查找了網上比較多的資料來總結cookie的一些知識,文筆有限,有誤之處,歡迎指出