目錄
Cookie
什么是Cookie
Cookie分類
Cookie版本
Cookie工作原理
Cookie詳解
創建cookie
cookie編碼
cookie過期時間選項
Cookie流程
Cookie使用
會話管理
個性化信息
記錄用戶的行為
Cookie屬性
domain選項
path選項
secure選項
cookie使用失效日期
httponly
cookie自動刪除
Cookie的缺陷
HTTP Cookie總結
HTTP Session工作流程總結
傳輸安全
Session和Cookie的區別
報文分類與格式
HTTP響應報文
狀態行(Status-Line)
響應頭部(Response Header Fields)
消息體(Message Body)
Cookie
什么是Cookie
HTTP Cookie(也叫 Web Cookie 或瀏覽器 Cookie)是服務器發送到用戶瀏覽器并保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶并發送到服務器上。
通常,它用于告知服務端兩個請求是否來自同一瀏覽器,如保持用戶的登錄狀態。Cookie 使基于無狀態的 HTTP?協議記錄穩定的狀態信息成為了可能。
Cookie分類
會話 Cookie:會話 Cookie 是臨時 Cookie,當前會話結束(瀏覽器退出)時 Cookie 會被刪除。會話 Cookie 和持久 Cookie 的區別在于過期時間,如果設置了 Discard 參數(Cookie 版本1)或者沒有設置 Expires(Cookie 版本 0)或 Max-Age(Cookie 版本1)設置過期時間,則此 Cookie 為會話 Cookie。
持久 Cookie:持久 Cookie 會存儲在用戶的硬盤上,瀏覽器(客戶端)退出,然后重新啟動后 Cookie 仍然存在。
Cookie版本
Cookie 有兩個版本,一個是版本 0(Netscape Cookies)和版本 1(RFC 2965),目前大多數服務器使用的 Cookie 0。
Cookie工作原理
Cookie 就像服務器給用戶貼的標簽,用戶訪問一個 web 站點的時候,服務器就可以通過這個標簽來識別是哪一個用戶。Cookie 中包含了一個有名字=值(name=value)這樣的信息構成的任意列表,并通過 Set-Cookie?或 Set-Cookie2 Http 響應(擴展)的 header 來設置標簽。
cooke 可以包含任意信息,但他們通常都只包含一個服務器為了進行追蹤而產生的獨特的識別碼。瀏覽器會記住從服務器返回的 Set-Cookie 或 Set-Cookie2 header 中的 Cookie 內容,并將 Cookie 集存儲在瀏覽器的 Cookie 數據庫中。將來用戶訪問統一站點時,瀏覽器會選中那個服務器貼到用戶上的那些 Cookie,并請求的 header 中將起傳給服務器。
Cookie詳解
創建cookie
Web 服務器通過發送一個稱為?Set-Cookie 的 HTTP 消息頭來創建一個 cookie,Set-Cookie 消息頭是一個字符串,其格式如下(中括號中的部分是可選的):
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
消息頭的第一部分,value 部分,通常是一個 name=value 格式的字符串。事實上,這種格式是原始規范中指定的格式,但是瀏覽器并不會對 cookie 值按照此格式來驗證。實際上,你可以指定一個不含等號的字符串,它同樣會被存儲。然而,最常用的使用方式是按照 name=value 格式來指定 cookie 的值(大多數接口只支持該格式)。
當存在一個 cookie,并允許設置可選項,該 cookie 的值會在隨后的每次請求中被發送至服務器,cookie 的值被存儲在名為 Cookie 的 HTTP 消息頭中,并且只包含了 cookie 的值,忽略全部設置選項。例如:
Cookie: value
通過 Set-Cookie 指定的可選項只會在瀏覽器端使用,而不會被發送至服務器端。發送至服務器的 cookie 的值與通過 Set-Cookie 指定的值完全一樣,不會有進一步的解析或轉碼操作。如果請求中包含多個 cookie,它們將會被分號和空格分開,例如:
Cookie: value1; value2; name1=value1
服務器端框架通常包含解析 cookie 的方法,可以通過編程的方式獲取 cookie 的值。
cookie編碼
對于 cookie 的值進行編碼一直都存在一些困惑。普遍認為 cookie 的值必須經過 URL 編碼,但其實這是一個謬論,盡管通常都這么做。原始規范中明確指出只有三個字符必須進行編碼:分號、逗號和空格,規范中還提到可以進行 URL 編碼,但并不是必須,在 RFC 中沒有提及任何編碼。然而,幾乎所有的實現都對 cookie 的值進行了一系列的 URL 編碼。對于 name=value 格式,通常會對 name 和 value 分別進行編碼,而不對等號 = 進行編碼操作。
cookie過期時間選項
緊跟 cookie 值后面的每個選項都以分號和空格分開,每個選擇都指定了 cookie 在什么情況下應該被發送至服務器。第一個選項是過期時間(expires),指定了 cookie 何時不會再被發送至服務器,隨后瀏覽器將刪除該 cookie。該選項的值是一個 Wdy, DD-Mon-YYYY HH:MM:SS GMT 日期格式的值,例如:
Set-Cookie: name=Nicholas; expires=Sat, 02 May 2009 23:38:25 GMT
沒有設置 expires 選項時,cookie 的生命周期僅限于當前會話中,關閉瀏覽器意味著這次會話的結束,所以會話 cookie 僅存在于瀏覽器打開狀態之下。這就是為什么為什么當你登錄一個 Web 應用時經常會看到一個復選框,詢問你是否記住登錄信息:如果你勾選了復選框,那么一個 expires 選項會被附加到登錄 cookie 中。如果 expires 設置了一個過去的時間點,那么這個 cookie 會被立即刪掉。
Cookie流程
大部分 web 網站都會使用到 cookie,使用它的基本流程可以概括為 3 步,瀏覽器向服務器請求一個從未請求過的 web 頁面:
GET?/index.html?HTTP/1.1Host: www.haicoder.net
...
瀏覽器會在接下來的 http 請求的 header 中把以上 cookie 原樣返回給服務器:
HTTP/1.0 200?OKContent-type: text/htmlSet-Cookie: theme=lightSet-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2020 10:18:14 GMT
...
服務器返回瀏覽器此頁面,并在返回 http 包的 header 中設置 set-cookie 屬性:
GET?/spec.html?HTTP/1.1Host: www.haicoder.netCookie: theme=light; sessionToken=abc123
…
上面示例設置了兩個 cookies: 第一個是 theme,由于沒有設置它的 Expires 或 Max-Age 屬性,所以是個 session cookie,它會在瀏覽器關閉時直接被刪除掉。 第二個是 SessionToken,它有過期時間,所以只會在指定的過期時間后才會被刪除(也可手動刪除)。
瀏覽器訪問時,會把上一步的 cookies 設置在 header 中原樣返回給服務器,當然不需要再指定 cookie 的其它屬性,只需要把 key-value 返回即可。服務器根據設置的 cookies 就能知道標識這個客戶,把無狀態的 HTTP 請求變成了有狀態的請求。
瀏覽器的 Cookie 頭部信息如下:
Cookie使用
會話管理
- 記錄用戶的登錄狀態是 cookie 最常用的用途。通常 web 服務器會在用戶登錄成功后下發一個簽名來標記 session 的有效性,這樣免去了用戶多次認證和登錄網站。
- 記錄用戶的訪問狀態,例如導航啊,用戶的注冊流程啊。
個性化信息
- Cookie 也經常用來記憶用戶相關的信息,以方便用戶在使用和自己相關的站點服務。例如:ptlogin 會記憶上一次登錄的用戶的 QQ 號碼,這樣在下次登錄的時候會默認填寫好這個 QQ 號碼。
- Cookie 也被用來記憶用戶自定義的一些功能。用戶在設置自定義特征的時候,僅僅是保存在用戶的瀏覽器中,在下一次訪問的時候服務器會根據用戶本地的 cookie 來表現用戶的設置。例如 google 將搜索設置(使用語言、每頁的條數,以及打開搜索結果的方式等等)保存在一個 COOKIE 里。
記錄用戶的行為
最典型的是公司的 TCSS 系統。它使用 Cookie 來記錄用戶的點擊流和某個產品或商業行為的操作率和流失率。當然功能可以通過 IP 或 http header 中的 referrer 實現,但是 Cookie 更精準一些。
Cookie屬性
一般 Cookie 所具有的屬性,包括:
domain選項
domain,指定了 cookie 將要被發送至哪個或哪些域中。默認情況下,domain 會被設置為創建該 cookie 的頁面所在的域名,所以當給相同域名發送請求時該 cookie 會被發送至服務器。domain 選項可用來擴充 cookie 可發送域的數量,例如:
Set-Cookie: name=Nicholas; domain=haicoder.net
像 Yahoo! 這種大型網站,都會有許多 name.yahoo.com 形式的站點(例如:my.yahoo.com, finance.yahoo.com 等等)。將一個 cookie 的 domain 選項設置為 yahoo.com,就可以將該 cookie 的值發送至所有這些站點。瀏覽器會把 domain 的值與請求的域名做一個尾部比較(即從字符串的尾部開始比較),并將匹配的 cookie 發送至服務器。domain 選項的值必須是發送 Set-Cookie 消息頭的主機名的一部分,例如我不能在 google.com 上設置一個 cookie,因為這會產生安全問題。不合法的 domain 選擇將直接被忽略。
path選項
另一個控制 Cookie 消息頭發送時機的選項是 path 選項,和 domain 選項類似,path 選項指定了請求的資源 URL 中必須存在指定的路徑時,才會發送 Cookie 消息頭。這個比較通常是將 path 選項的值與請求的 URL 從頭開始逐字符比較完成的。如果字符匹配,則發送 Cookie 消息頭,例如:
Set-Cookie:name=Nicholas;path=/blog
在這個例子中,path 選項值會與 /blog,/blogtool 等等相匹配;任何以 /blog 開頭的選項都是合法的。需要注意的是,只有在 domain 選項核實完畢之后才會對 path 屬性進行比較。path 屬性的默認值是發送 Set-Cookie 消息頭所對應的 URL 中的 path 部分。
secure選項
最后一個選項是 secure。不像其它選項,該選項只是一個標記而沒有值。只有當一個請求通過 SSL 或 HTTPS?創建時,包含 secure 選項的 cookie 才能被發送至服務器。這種 cookie 的內容具有很高的價值,如果以純文本形式傳遞很有可能被篡改,例如:
Set-Cookie: name=Nicholas; secure
事實上,機密且敏感的信息絕不應該在 cookie 中存儲或傳輸,因為 cookie 的整個機制原本都是不安全的。默認情況下,在 HTTPS 鏈接上傳輸的 cookie 都會被自動添加上 secure 選項。
cookie使用失效日期
當 cookie 創建時指定了失效日期,這個失效日期則關聯了以 name-domain-path-secure 為標識的 cookie。要改變一個 cookie 的失效日期,你必須指定同樣的組合。當改變一個 cookie 的值時,你不必每次都設置失效日期,因為它不是 cookie 標識信息的組成部分。例如:
Set-Cookie:name=Mike;expires=Sat,03 May 2025 17:44:22 GMT
現在已經設置了 cookie 的失效日期,所以下次我想要改變 cookie 的值時,我只需要使用它的名字:
Set-Cookie:name=Matt
cookie 的失效日期并沒有改變,因為 cookie 的標識符是相同的。實際上,只有你手工的改變 cookie 的失效日期,否則其失效日期不會改變。這意味著在同一個會話中,一個會話 cookie 可以變成一個持久化 cookie(一個可以在多個會話中存在的),反之則不可。為了要將一個持久化 cookie 變為一個會話 cookie,你必須刪除這個持久化 cookie,這只要設置它的失效日期為過去某個時間之后再創建一個同名的會話 cookie 就可以實現。
需要記得的是失效日期是以瀏覽器運行的電腦上的系統時間為基準進行核實的。沒有任何辦法來來驗證這個系統時間是否和服務器的時間同步,所以當服務器時間和瀏覽器所處系統時間存在差異時這樣的設置會出現錯誤。
httponly
表示此 Cookie 必須用于 http 或 https 傳輸。這意味著,瀏覽器腳本,比如 javascript?中,是不允許訪問操作此 Cookie 的。
cookie自動刪除
cookie 會被瀏覽器自動刪除,通常存在以下幾種原因:
- 會話 cooke (Session cookie) 在會話結束時(瀏覽器關閉)會被刪除。
- 持久化 cookie(Persistent cookie)在到達失效日期時會被刪除。
- 如果瀏覽器中的 cookie 數量達到限制,那么 cookie 會被刪除以為新建的 cookie 創建空間。
Cookie的缺陷
- cookie 會被附加在每個 HTTP 請求中,所以無形中增加了流量。
- 由于在 HTTP 請求中的 cookie 是明文傳遞的,所以安全性成問題。(除非用 HTTPS)
- Cookie 的大小限制在 4KB 左右。對于復雜的存儲需求來說是不夠用的。
HTTP Cookie總結
HTTP Cookie(也叫 Web Cookie 或瀏覽器 Cookie)是服務器發送到用戶瀏覽器并保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶并發送到服務器上。
通常,它用于告知服務端兩個請求是否來自同一瀏覽器,如保持用戶的登錄狀態。Cookie 使基于無狀態的 HTTP 協議記錄穩定的狀態信息成為了可能。
HTTP Session工作流程總結
- 瀏覽器第一次請求網站, 服務端生成 Session ID。
- 把生成的 Session ID 保存到服務端存儲中。
- 把生成的 Session ID 返回給瀏覽器,通過 set-cookie。
- 瀏覽器收到 Session ID, 在下一次發送請求時就會帶上這個 Session ID。
- 服務端收到瀏覽器發來的 Session ID,從 Session 存儲中找到用戶狀態數據,會話建立。
- 此后的請求都會交換這個 Session ID,進行有狀態的會話。
傳輸安全
最后再聊聊傳輸安全,有一種叫做 Session ID 劫持的,假如 Session ID 是基于 HTTP 協議傳輸的,因為是明文傳輸,那么它就可能被中間的路由器劫持。 攻擊者得到 Session ID 后,把它帶到自己的請求中,就能夠進入你的賬戶。
所以一些 Web 框架還提供了 Session 的一些安全保護,比如間隔時間內動態刷新 Session ID,加上 Token 等
Session和Cookie的區別
- cookie 數據存放在客戶端,session 數據放在服務器上。
- cookie 不是很安全,別人可以分析存放在本地的 Cookie 并進行 Cookie 欺騙考慮到安全應當使用 session。
- session 會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能考慮到減輕服務器性能方面,應當使用 Cookie。
- 單個 Cookie 保存的數據長度不能超過 4K,很多瀏覽器都限制一個網址最多保存 20 個 cookie。
- 將登陸信息等重要信息存放為 SESSION,其他信息如果需要保留,可以放在 COOKIE 中。
- Session 的運行依賴 Session ID,而 Session ID 是存在 Cookie 中的,也就是說,如果瀏覽器禁用了 Cookie,Session 也會失效(但是可以通過其它方式實現,比如在 url 中傳遞 Session ID)。
報文分類與格式
所有的 HTTP 報文都可以分為兩類:請求報文和響應報文。請求和響應報文的基本報文結構相同。請求報文的格式:
<method> <request-URL> <version>
<headers>
<entity-body>
?
響應報文的格式(注意,只有起始行的語法有所不同):
<version> <status> <reason-phrase>
<headers>
<entity-body>
HTTP響應報文
一個 http 響應報文也由四個部分組成:
- 狀態行(Status-Line)
- 響應頭部(Response Header Fields)
- 回車換行(CRLF)
- 消息體(Message Body)
狀態行(Status-Line)
HTTP/1.1 200?OK
上面是一個典型的 http 響應狀態行,我們可以看到也是由三部分組成的:
- http 協議版本
- 狀態碼(Status Code)
- 狀態碼的文本描述(Reason-Phrase)
響應頭部(Response Header Fields)
和請求頭部類似,就是兩者之間有一些不同的頭部字段。
消息體(Message Body)
返回給客戶端的具體消息。