HTTP cookies 詳解

 
標籤: httpcookies
 分類:

    HTTP cookies,一般又稱做"cookies",已經存在了很長時間,可是仍舊沒有被予以充分的理解。首要的問題是存在了諸多誤區,認爲cookies是後門程序或病毒,或壓根不知道它是如何工做的。第二個問題是對於cookies缺乏一個一致性的接口。儘管存在着這些問題,cookies仍舊在web開發中起着如此重要的做用,以致於若是cookie在沒有可替代品出現的狀況下消失,咱們許多喜歡的Web應用將變得毫無用處。javascript

       cookies的起源php

       早期Web開發面臨的最大問題之一是如何管理狀態。簡言之,服務器端沒有辦法知道兩個請求是否來自於同一個瀏覽器。那時的辦法是在請求的頁面中插入一個token,而且在下一次請求中將這個token返回(至服務器)。這就須要在form中插入一個包含token的隱藏表單域,或着在URL的qurey字符串中傳遞該token。這兩種辦法都強調手工操做而且極易出錯。html

       Lou Montulli,那時是網景通信的一個僱員,被認爲在1994年將「magic cookies」的概念應用到了web通信中。他意圖解決的是web中的購物車,如今全部購物網站都依賴購物車。他的最先的說明文檔提供了一些cookies工做原理的基本信息該文檔在RFC2109中被規範化(這是全部瀏覽器實現cookies的參考依據),而且最終逐步造成了REF2965.Montulli最終也被授予了關於cookies的美國專利。網景瀏覽器在它的第一個版本中就開始支持cookies,而且當前全部web瀏覽器都支持cookies。前端

       cookie是什麼?java

       坦白的說,一個cookie就是存儲在用戶主機瀏覽器中的一小段文本文件。Cookies是純文本形式,它們不包含任何可執行代碼。一個Web頁面或服務器告之瀏覽器來將這些信息存儲而且基於一系列規則在以後的每一個請求中都將該信息返回至服務器。Web服務器以後能夠利用這些信息來標識用戶。多數須要登陸的站點一般會在你的認證信息經過後來設置一個cookie,以後只要這個cookie存在而且合法,你就能夠自由的瀏覽這個站點的全部部分。再次,cookie只是包含了數據,就其自己而言並不有害。web

       建立cookie算法

       經過HTTP的Set-Cookie消息頭,Web服務器能夠指定存儲一個cookie。Set-Cookie消息的格式以下面的字符串(中括號中的部分都是可選的)編程

1 Set-Cookie:value [ ;expires=date][ ;domain=domain][ ;path=path][ ;secure]

      消息頭的第一部分,value部分,一般是一個name=value格式的字符串。事實上,原始手冊指示這是應該使用的格式,可是瀏覽器對cookie的全部值並不會按此格式校驗。實際上,你能夠指定一個不包含等號的字符串而且它一樣會被存儲。然而,一般性的使用方式是以name=value的格式(而且多數的接口只支持該格式)來指定cookie的值。瀏覽器

       當一個cookie存在,而且可選條件容許的話,該cookie的值會在接下來的每一個請求中被髮送至服務器。cookie的值被存儲在名爲Cookie的HTTP消息頭中,而且只包含了cookie的值,其它的選項所有被去除。例如:        安全

1 Cookie : value

       經過Set-Cookie指定的選項只是應用於瀏覽器端,一旦選項被設置後便不會被服務器從新取回。cookie的值與Set-Cookie中指定的值是徹底同樣的字符串;對於這些值不會有更近一步的解析或轉碼操做。若是在指定的請求中有多個cookies,那麼它們會被分號和空格分開,例如:

1 Cookie:value1 ; value2 ; name1=value1

 

      服務器端框架一般會提供解析cookies的功能,而且經過編程方式獲取cookies的值。

      cookie編碼(cookie encoding)

      對於cookie的值進行編碼一直都存在一些困惑。一般的觀點是cookie的值必須被URL編碼,可是這實際上是一個謬誤,儘管能夠對cookie的值進行URL編碼。原始的文檔中指示僅有三種類型的字符必須進行編碼:分號,逗號,和空格。規範中提到能夠利用URL編碼,可是並非必須。RFC沒有說起任何的編碼。然而,幾乎全部的實現方式都對cookie的值進行了一些列的URL編碼。對於name=value的格式,name和value一般都單獨進行編碼而且不對等號「=」進行編碼操做。

      有效期選項(The expires  option)

      緊跟cookie值後面的每一個選項都以分號和空格分割,而且每一個選項都指定cookie什麼時候應該被髮送到服務器。第一個選項是expires,其指定了cookie什麼時候不會再被髮送到服務器端的,所以該cookie可能會被瀏覽器刪掉。該選項所對應的值是一個格式爲Wdy,DD-Mon--YYYY HH:MM:SS GMT的值,例如:

1 Set-Cookie:name=Nicholas;expires=Sat, 02 May 2009 23:38:25 GMT

      在沒有expires選項時,cookie的壽命僅限於單一的會話中。瀏覽器的關閉意味這一次會話的結束,因此會話cookie只存在於瀏覽器保持打開的狀態之下。這就是爲何當你登陸到一個web應用時常常看到一個checkbox,詢問你是否選擇存儲你的登陸信息:若是你選擇是的話,那麼一個expires選項會被附加到登陸的cookie中。若是expires選項設置了一個過去的時間點,那麼這個cookie會被當即刪除。

       domain選項(The domain option)

      下一個選項是domain,指示cookie將要發送到哪一個域或那些域中。默認狀況下,domain會被設置爲建立該cookie的頁面所在的域名。例如本站中的cookie的domain屬性的默認值爲www.nczonline.com。domain選項被用來擴展cookie值所要發送域的數量。例如:

1 Set-Cookie:name=Nicholas;domain=nczonline.net

       想象諸如Yahoo這樣的大型網站都會有許多以name.yahoo.com(例如:my.yahoo.com,finance.yahoo.com,等等)爲格式的站點。單獨的一個cookie能夠簡單的經過將其domain選項設置爲yahoo.com而發送到全部這些站點中。瀏覽器會對domain的值與請求所要發送至的域名,作一個尾部比較(即從字符串的尾部開始比較),而且在匹配後發送一個Cookie消息頭。

      domain設置的值必須是發送Set-Cookie消息頭的域名。例如,我沒法向google.com發送一個cookie,由於這個產生安全問題。不合法的domain選項只要簡單的忽略便可。

        Path選項(The path option)

       另外一個控制什麼時候發送Cookie消息頭的方式是指定path選項。與domain選項相同的是,path指明瞭在發Cookie消息頭以前必須在請求資源中存在一個URL路徑。這個比較是經過將path屬性值與請求的URL從頭開始逐字符串比較完成的。若是字符匹配,則發送Cookie消息頭,例如:

1 Set-Cookie:name=Nicholas;path=/blog

 

       在這個例子中,path選項值會與/blog,/blogrool等等相匹配;任何以/blog開頭的選項都是合法的。要注意的是隻有在domain選項覈實完畢以後纔會對path屬性進行比較。path屬性的默認值是發送Set-Cookie消息頭所對應的URL中的path部分。

        secure選項(The  secure  option)

      最後一個選項是secure。不像其它選項,該選項只是一個標記而且沒有其它的值。一個secure cookie只有當請求是經過SSL和HTTPS建立時,纔會發送到服務器端。這種cookie的內容意指具備很高的價值而且可能潛在的被破解以純文本形式傳輸。例如

1 Set-Cookie:name=Nicholas;secure

      現實中,機密且敏感的信息毫不應該在cookies中存儲或傳輸,由於cookies的整個機制都是本來不安全的。默認狀況下,在HTTPS連接上傳輸的cookies都會被自動添加上secure選項。

        cookie的維護和生命週期(cookie maintenance and lifecycle)

       任意數量的選項均可以在單一的cookie中指定,而且這些選項能夠以任何順序存在,例如

1 Set-Cookie:name=Nicholas; domain=nczonline.net; path=/blog

 

       這個cooke有四個標識符:cookie的name,domain,path,secure標記。要想在未來改變這個cookie的值,須要發送另外一個具備相同cookie name,domain,path的Set-Cookie消息頭。例如:

1 Set-Cooke:name=Greg; domain=nczonline.net; path=/blog

 

       這將以一個新的值來覆蓋原來cookie的值。然而,僅僅只是改變這些選項的某一個也會建立一個徹底不一樣的cookie,例如:

1 Set-Cookie:name=Nicholas; domain=nczonline.net; path=/

        在返回這個消息頭後,會存在兩個同時擁有「name」的不一樣的cookie。若是你訪問在www.nczonline.NET/blog下的一個頁面,如下的消息頭將被包含進來:

1 Cookie:name=Greg;name=Nicholas

       在這個消息頭中存在了兩個名爲「name」的cookie,path值越詳細則cookie越靠前。domain-path越詳細則cookie字符串越靠前。假設我在ww.nczonline.Net/blog下而且發送了另外一個cookie,其設置以下:

1 Set-Cookie:name=Mike

       那麼返回的消息頭如今則變爲:

1 Cookie:name=Mike;name=Greg;name=Nicholas

       因爲包含「Mike」的cookie使用了域名(www.nczonline.net)做爲其domain值而且以全路徑(/blog)做爲其path值,則它較其它兩個cookie更加詳細。

    使用失效日期(using expiration dates)

       當cookie建立時包含了失效日期,這個失效日期則關聯了以name-domain-path-secure爲標識的cookie。要改變一個cookie的失效日期,你必須指定一樣的組合。當改變一個cookie的值時,你沒必要每次都設置失效日期,由於它不是cookie標識信息的組成部分。例如:

1 Set-Cookie:name=Mike;expires=Sat,03 May 2025 17:44:22 GMT

 

        如今已經設置了cookie的失效日期,因此下次我想要改變cookie的值時,我只須要使用它的名字:

1 Set-Cookie:name=Matt

 

       在cookie上的失效日期並無改變,由於cookie的標識符是相同的。實際上,只有你手工的改變cookie的失效日期,不然其失效日期不會改變。這意味着在同一個會話中,一個會話cookie能夠變成一個持久化cookie(一個能夠在多個會話中存在的),反之則不可。爲了要將一個持久化cookie變爲一個會話cookie,你必須刪除這個持久化cookie,這隻要設置它的失效日期爲過去某個時間以後再建立一個同名的會話cookie就能夠實現。

       須要記得的是失效日期是以瀏覽器運行的電腦上的系統時間爲基準進行覈實的。沒有任何辦法來來驗證這個系統時間是否和服務器的時間同步,因此當服務器時間和瀏覽器所處系統時間存在差別時這樣的設置會出現錯誤。

       cookie自動刪除(automatic cookie removal)

       cookie會被瀏覽器自動刪除,一般存在如下幾種緣由:

  • 會話cooke(Session cookie)在會話結束時(瀏覽器關閉)會被刪除
  • 持久化cookie(Persistent cookie)在到達失效日期時會被刪除
  • 若是瀏覽器中的cookie限制到達,那麼cookies會被刪除覺得新建cookies建立空間。詳見個人另一篇關於cookies restrictions的博客

       對於任何這些自動刪除來講,Cookie管理顯得十分重要,由於這些刪除都是無心識的。

       Cookie限制條件(Cookie restrictions)

       在cookies上存在了諸多限制條件,來阻止cookie濫用並保護瀏覽器和服務器免受一些負面影響。有兩種cookies的限制條件:cookies的屬性和cookies的總大小。原始的規範中限定每一個域名下不超過20個cookies,早期的瀏覽器都遵循該規範,而且在IE7中有個更近一步的提高。在微軟的一次更新中,他們在IE7中增長cookies的限制到50個,與此同時Opera限定cookies個數爲30.Safari和Chrome對與每一個域名下的cookies個數沒有限制。

       發向服務器的全部cookies的最大數量(空間)仍舊維持原始規範中所指出的:4KB。全部超出該限制的cookies都會被截掉而且不會發送至服務器。

        Subcookies

       鑑於cookie的數量限制,開發者提出的subcookies的觀點來增長cookies的存儲量。Subcookies是一些存儲在一個cookie的value中的一些name-value對,而且一般與如下格式相似:

1 name=a=b&c=d&e=f&g=h

      這種方式容許在單個cookie中保存多個name-value對,而不會超過瀏覽器cookie的數量限制。經過這種方式建立cookies的負面影響是,須要自定義解析方式來提取這些值,相比較而言cookies的格式會更爲簡單。服務器端框架已開始支持subcookies的存儲。我編寫的YUI Cookie utility,支持在JavaScript中讀/寫subcookies

        Javascript中的cookie(cookie In Javascript)

       經過Javascript中的document.cookie屬性,你能夠建立,維護和刪除cookies。當要建立cookies時該屬性等同於Set-Cookie消息頭,而在讀取cookie時則等同於Cookie消息頭。在建立一個cookie時,你須要使用和Set-Cookie指望格式相同的字符串:

1 document.cookie="name=Nicholas;domain=nczonline.net;path=/";

       設置document.cookie屬性的值並不會刪除存儲在頁面中的全部cookies。它只簡單的建立或修改字符串中指定的cookies。下次發送一個請求到服務器時,這些cookies(經過document.cookie設置的)會和其它經過Set-Cookie消息頭設置的cookies同樣發送至服務器。全部這些cookies並無什麼明確的不一樣之處。

       要使用Javascript提取cookie的值時,只要從document.cookie中讀取便可。返回的字符串與Cookie消息頭中的字符串格式相同,因此多個cookies會被分號和字符串分割。例如:

1 name1=Greg; name2=Nicholas

        鑑於此,你須要手工解析這個cookie字符串來提取真實的cookie數據。當前已有許多描述利用Javascript來解析cookie的資料,包括個人書,Professional Javascript,因此在這我就再也不說明。一般利用已存在的Javascript庫操做cookie會更簡單,如YUI Cookie utility 來在Javascript中處理cookies而不要手工從新建立這些算法

        經過訪問document.cookie返回的cookies遵循發向服務器的cookies同樣的訪問規則。要經過Javascript訪問cookies,該頁面和cookies必須在相同的域中,有相同的path,有相同的安全級別。

       注意:一旦cookies經過Javascript設置後遍不能提取它的選項,因此你將不會知道domain,path,expiration日期或secure標記。

        HTTP-Only cookies

       微軟的IE6 SP1在cookies中引入了一個新的選項:HTTP-only cookies.HTTP-Only背後的意思是告之瀏覽器該cookie毫不應該經過Javascript的document.cookie屬性訪問。設計該特徵意在提供一個安全措施來幫助阻止經過Javascript發起的跨站腳本攻擊(XSS)竊取cookie的行爲(我會在另外一篇博客中討論安全問題,本篇如此已足夠)。今天Firefox2.0.0.5+,Opera9.5+,Chrome都支持HTTP-Only cookies。3.2版本的Safari仍不支持。

       要建立一個HTTP-Only cookie,只要向你的cookie中添加一個HTTP-Only標記便可:

1 Set-Cookie: name=Nicholas; HttpOnly

 

       一旦設定這個標記,經過documen.coookie則不能再訪問該cookie。IE同時更近一步而且不容許經過XMLHttpRequest的getAllResponseHeaders()或getResponseHeader()方法訪問cookie,然而其它瀏覽器則容許此行爲。Firefox在3.0.6中修復了該漏洞,然而仍舊有許多瀏覽器漏洞存在,complete browser support list列出了這些。

      你不能經過JavaScript設置HTTP-only cookies,由於你不能再經過JavaScript讀取這些cookies,這是情理之中的事情。

      總結(conclusion)

      爲了高效的利用cookies,仍舊有許多要了解和弄明白的東西。對於一項建立於十多年前但仍舊如最初實現的那樣被使用至今的技術來講,這是件多難以想象的事。本篇只是提供了一些每一個人都應該知道的關於瀏覽器cookies的基本指導,但不管如何,也不是一個完整的參考。對於今天的web來講Cookies仍舊起着很是重要的做用,而且不恰當的管理cookies會致使各類安全性的問題,從最糟糕的用戶體驗到安全漏洞。我但願這篇手冊可以激起一些關於cookies的難以想象的亮點。

     寫在後面的:

     該文章是2009年的,到如今可能已經算一篇比較老的文章,可是文章中關於cookies的講解十分詳細,最近在學習cookies時,讀到該文章,以爲值得你們一讀,同時也做爲本身的參考吧,因此將原文翻譯爲中文。文中較爲詳細的講解了關於cookies的起源,所要解決的問題,以及cookies的自己的屬性和每一個屬性的做用,以及相關瀏覽器對於cookies的實現狀況和延伸狀況,正如做者所表達的那樣,cookies做爲一項十幾年前建立卻一直沿用至今的技術,值得每一個開發者思考並瞭解和弄明白關於cookies的一些基本信息和原理,譯文中儘可能保證還原原文本意,但水平有限,一些語句翻譯的比較生澀,建議和原文對比閱讀,效果可能會比較好一點。

    關於做者: Nicholas C. Zakas,資深前端工程師,曾在yahoo工做近五年,並擔任前端開發技術領導,他的著做有《javascript 高級程序設計》是一本高質量的前端技術著做。

相關文章
相關標籤/搜索