[轉貼] 談談 Cookie 特性

2018070810:38
出處:http://www.dotblogs.com.tw/jasonyah/archive/2013/10/06/explain-http-cookie-in-detail.aspx

前言
身為 Web 開發人員,不管你今天是寫 PHP、ASP.NET … 等,一定都有聽過 Cookie,正所謂「工欲善其事,必先利其器」,而常見的 Cookie 會用來記錄使用者的登入資訊,但又有多少人是真正了解 Cookie 的特性呢,我想每個網頁開發人員應該都要確切了解 Cookie 的特性,以免哪天寫的程式碼有了漏洞讓駭客成功竊取到相關資訊,或是存了太多 Cookie 在同一個頁面而拖慢了網站的速度,今天舊讓我們來談談 Cookie 吧!
概觀
簡單來說 Cookie 是將網站所需使用的資訊存放在 Client 端的瀏覽器上,而在每次瀏覽器和 Web 伺服器在進行資料交換時,同時也會將相關的 Cookie 傳到 Web 伺服器上,簡單來說 Cookie 的運作過程大致如下:
  1. Client 端向 Web Server 要求某個網頁,同時也會將符合的 Cookie 資訊傳送到 Server 端
  2. 當 Client 端取得 Server 端返回的網頁時,瀏覽器會將返回回來的 Cookie 資料記錄到電腦的資料夾中

利用開發工具可以看到每次瀏覽器請求網頁時,會一併將 Cookie 的資訊傳送到 Server 端
1
當 Server 端將網頁回傳給瀏覽器時,透過 Set-Cookie 這個 Header 來告訴 Client 端需要在瀏覽器中加入一或多個 Cookie,並且記錄該 Cookie 的隸屬網域(Domain)、存放目錄(Path)、過期時間(Expires) 等資訊。
2
假設 Brower 取得某網頁,且包含了 5 個 CSS 、2 個 Javascript 檔案,在這一次的 Request 中就會將同樣的 Cookie 送出 7 次,可想而知 Cookie 絕對不是越多越好,而是需要小心地使用它,另外也因為 Cookie 是儲存在 Client 端,我們就可以透過 Javascript 或是第三方軟體來取得或修改網頁裡的 Cookie,若你的 Cookie 中包含了帳號密碼等敏感性資訊,這樣一來駭客就可以輕而易舉的冒用他人的 Cookie 來登入你的網站,所以在開發 Web 系統時,針對 Cookie 部分也需要特別注意。
Cookie 限制
雖然 Cookie 是儲存在 Client 端中,但不代表就像儲存檔案一樣可以肆無忌憚的儲存,基於 RFC2965 的規範,定義了瀏覽器對於 Cookie 的最低儲存量,而因為每家瀏覽器的限制不同,但至少都須符合 RFC 規範,大致的定義為:
  1. 每個 Cookie 所能存放的大小為 4096 Bytes
  2. 每個網域至少可以儲存 20 個 Cookies,若儲存超過限制大小瀏覽器會捨棄最舊的 Cookie。
  3. 至少能儲存 300 個 Cookies
Cookie 屬性介紹
  1. Expires – 設定 Cookie 的有效日期,若沒有設定預設 Cookie 會保存到瀏覽器關閉為止
       1: Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(1);
  2. Secure - 設定 Cookie 僅在使用 HTTPS 時才會送出去 
       1: Response.Cookies["UserName"].Secure = true; // 是否是 Https 狀態下才能發送
  3. Path - 限制該 Cookie 只能由某個資料夾或應用程式存取 
       1: Response.Cookies["UserName"].Path = "/Web1";

    舉例來說點部落的網址為 www.dotblogs.com.tw ,若我們將 Path 屬性設定為 "/Web1" ,代表只有在www.dotblogs.com.tw/Web1 這個網站底下的網頁才能使用該 Cookie,若沒有設定預設為 "/" 根目錄,代表該網域底下的所有網站都能取得該 Cookie
     
  4. Domain - 限制 Cookie 的網域範圍 
       1: //直接指定網站的網域名稱,若沒有額外設定則該 Cookie 僅能被當前的網域所存取
       2: Response.Cookies["UserName"].Domain = "www.dotblogs.com";
       3:  
       4: // *.dotblogs.com 網域的所有網站都能接收此 Cookie
       5: Response.Cookies["LoginTime"].Domain = "dotblogs.com";

    PS:一般常見的 SSO (Single Sign-On) 機制,也會利用設定網域的方式來讓不同子網域的網站也能存取到同一個 Cookie 設定,以達到跨網域登入。
    PS:不能設定跟自己不一樣的網域,Ex: www.dotblogs.com.tw 的網站在設定 Cookie 時就不能指定 facebook.com 的 Cookie。
     
  5. HttpOnly - 設定 Cookie 是否能由 Javascipt 所存取,預設為 false 能被 Javascript 所存取 
       1: //設定為 true 代表該 Cookie 不能被 Javascript 存取
       2: Response.Cookies["UserInfo"].HttpOnly = true;

    依前面所講的 Cookie 能被 Browser 的 Javascript 所取得,也讓駭客又多了一種方法來取得網站 Cookie 的資料,若網站的 Cookie 不需要被 Browser 端的 Javascript 使用,建議將 HttpOnly 的屬性設為 true
利用 ASP.NET 來操作 Cookie
  1. 新增 Cookie ,並設定值 
       1: HttpCookie MyCookie = new HttpCookie("UserInfo"); //新增 Cookie 名稱為 UserInfo
       2: MyCookie.Value = "JasonYah"; //設定 Cookie 的值
       3: Response.Cookies.Add(MyCookie);
  2. 取得從 Browser 送過來的 Cookie 
       1: if (Request.Cookies["UserInfo"] != null)
       2: {
       3:     var UserName = Request.Cookies["UserInfo"].Value;
       4: }
  3. 更新 Cookie 的到期時間 
       1: if (Request.Cookies["UserInfo"] != null)
       2: {
       3:     Request.Cookies["UserInfo"].Expires = DateTime.Now.AddHours(1);
       4: }
  4. 刪除 Browser 端的 Cookie 
       1: //將 Cookie 的到期時間設定為昨天,就可成功刪除
       2: Request.Cookies["UserInfo"].Expires = DateTime.Now.AddDays(-1);
       3: //或是利用 Remove 的方法來移除該 Cookie
       4: Request.Cookies.Remove("UserInfo");
  5. 建立一個含有多個值的 Cookie 
       1: HttpCookie MyCookie = new HttpCookie("UserInfo");
       2: MyCookie.Values["Name"] = "JasonYah";
       3: MyCookie.Values["Language"] = "zh-Tw";
       4: Response.Cookies.Add(MyCookie);

    前面有說到因為 Cookie 有限制數量及大小,一個網站最少能存放 20 個 Cookie,所以我們可以利用在單一 Cookie 中儲存多個 key/value 的方式來將相同性質的資訊存放在同一個 Cookie 當中。
總結
剛好前陣子有碰到,趁機會記錄起來,也希望能讓不理解 Cookie 的開發人員有一番認識,Cookie 在使用上也別記錄一些敏感性資訊,比如帳號密碼...等,就算真的記錄了也記得先經過加密,額外若 Cookie 是不會被 Javascript 給存取也記得加上 HttpOnly 的屬性,來增加你的網站安全。
參考連結