cookie

cookie的原理

何爲 cookie 呢?咱們在上面瞭解到 HTTP 是無狀態的,但隨着 Web 的不斷髮展,這種 無狀態 的特性出現了弊端。當你登陸到一家購物網站,在跳轉到該站的其餘頁面時也應該繼續保持登陸狀態。可是由於 HTTP 是無狀態的,因此必須得在瀏覽器端存儲一些信息來標識當前用戶,所以 cookie 應運而生,它一種瀏覽器管理狀態的文件。html

瀏覽器第一次發出請求,服務器會將 cookie 放入到響應請求中,在瀏覽器第二次發請求的時候,會把 cookie 帶過去,因而服務端就會辨別用戶身份。注意:單個 cookie 保存的數據不能超過 4K,不少瀏覽器都限制一個站點最多保存 20 個 cookie。前端

cookie 在請求頭中有一個 cookie 字段,在響應頭裏有一個 set-cookie 字段。web

cookie 是不可跨域的

cookie 自己就是用來保存一些隱私性的字段,基於安全性的考量,必需要保證它是 不可跨域的。咱們能夠作個實驗:先打開 google.com,而後在開發者工具中輸入如下代碼:express

document.cookie = 'hello=world;path=/;domain=.baidu.com';

document.cookie = 'world=hello;path=/;domain=.google.com';

複製代碼

打開 Application 選項卡,在側邊欄找到 Cookies,能夠發現只有 domain 爲 .google.com 的被成功添加。json

cookie 的屬性

咱們經過一個登陸的小例子來了解服務端設置 cookie。首先經過 express application generator 生成一個 Express 工程。後端

接着在 index.html 文件中輸入如下代碼,咱們建立一個輸入用戶名和密碼的界面,在點擊按鈕的時候,經過 fetch 將輸入的值發送給後端。跨域

<fieldset>
  <legend>Login</legend>
  <input id="userName" type="text" placeholder="請輸入用戶名" />
  <input id="userPwd" type="password" placeholder="請輸入密碼" />
  <button id="loginBtn">登陸</button>
</fieldset>

<p>登陸狀態: <span id="result"></span></p>
<script>
  const userName = document.getElementById('userName');
  const userPwd = document.getElementById('userPwd');
  const loginBtn = document.getElementById('loginBtn');
  const result = document.getElementById('result');

  loginBtn.addEventListener('click', function() {
    const data = {
      userName: userName.value,
      userPwd: userPwd.value
    };

    fetch('/login', {
      method: 'POST',
      headers: new Headers({
        'Content-Type': 'application/json'
      }),
      body: JSON.stringify(data)
    })
      .then(res => {
        return res.json();
      })
      .then(json => {
        result.innerHTML = json.msg;
      });
  });
</script>

複製代碼

當用戶名和密碼匹配時 (假設用戶名和密碼都是 yancey),返回給客戶端一個 cookie 以及登陸成功的 json;不然返回登陸失敗的 json。下面是模擬服務端登陸的接口。瀏覽器

router.post('/login', (req, res, next) => {
  const body = req.body;
  if (body.userName === 'yancey' && body.userPwd === 'yancey') {
    // 設置 cookie
    res.cookie('yancey', 'success');
    res.json({
      success: true,
      msg: '登陸成功'
    });
  } else {
    res.status(401).json({
      success: false,
      msg: '用戶名或密碼錯誤'
    });
  }
});

複製代碼

經過這個例子能夠看到,在 express 中,setCookie 的方式爲:第一個參數傳遞 name,第二個參數傳遞 value,注意瀏覽器會將元字符和語義字符以外的字符進行轉義。打開 Chrome 的開發者工具,就能夠看到該 cookie 被添加到瀏覽器上了。或者你在控制檯輸入 document.cookie,一樣能夠看到 cookie 字符串。安全

這只是一個設置 cookie 的簡單例子,cookie 有 7 種屬性可供使用,咱們一一來了解。bash

domain

該屬性給 cookie 設置 域名,默認爲當前網站的域名,下面的例子將 domain 設爲 yanceyleo.com,因爲前端頁面是 127.0.0.1,根據同源策略,該條 cookie 不會生效。

res.cookie('domain', 'domian', { domain: 'yanceyleo.com' });

複製代碼

expires / maxAge

httpOnly

當該屬性設爲 true 時,document.cookie 將沒法獲取該條 cookie,但服務端能夠照常得到。該屬性能夠有效的避免跨站腳本攻擊 (XSS)。 關於幾種腳本攻擊`

res.cookie('httpOnly', 'httpOnly', {
  // 只能被 web server 訪問到,也就是說在瀏覽器輸入 document.cookie 沒法取到該條 cookie,目的是防止 xss
  httpOnly: true
});

複製代碼

path

該屬性給 指定的路徑 添加此 cookie,默認爲 /。以下代碼就是給 users 這個路由設置 cookie (即使在服務端該路徑不存在也會被添加上)。

res.cookie('path', 'path', {
  path: '/users'
});

複製代碼

secure

只有當鏈接是 HTTPS 協議,該 cookie 纔會被添加。該屬性默認爲 fasle。由於我本地的 express 是 HTTP 協議,所以該條 cookie 不會生效。

res.cookie('secure', 'secure', {
  secure: true
});

複製代碼

signed (防篡改簽名)

該屬性是給瀏覽器發送一個加密的 cookie,該屬性默認爲 false。在 express 中,咱們可使用 cookie-parser 插件來建立一個加密後的 cookie。服務端經過該 cookie 的內容和簽名來檢驗它是否 被篡改

首先給 cookieParser 傳入一個 secret。

app.use(cookieParser('forcabarca'));

而後返回一個 sign 後的 cookie。

res.cookie('signed', 'signed', {
  signed: true
});

複製代碼

在 express 中,咱們可使用 req.cookies 來得到 未加密 的 cookie 對象,能夠經過 req.signedCookies 來得到 已加密 的 cookie 對象。

console.log(req.cookies); // { httpOnly: 'httpOnly' }
console.log(req.signedCookies); // { signed: 'signed' }

複製代碼

session

ession 是服務端使用的一種記錄客戶端狀態的機制,與 cookie 不一樣的是,session 保存在 服務端。當客戶端初次發送請求時 (好比登陸成功),服務端會將用戶信息以某種形式保存在服務端,當再次訪問時只需從該 session 中找到該客戶的狀態便可。

所以,cookie 機制就是經過檢查客戶身上的 「通行證」 來肯定客戶身份,而 session 則是經過檢查服務器上的 「客戶明細表」 來確認客戶身份。session 至關於程序在服務器上創建的一份客戶檔案,客戶來訪的時候只須要查詢客戶檔案表就能夠了。

由於 HTTP 是無狀態的,因此單純的 session 仍不能判斷是否爲究竟是哪一個用戶。所以服務端仍要向客戶端發送一個 maxAge 爲 -1 的 cookie 來做爲不一樣用戶的惟一標識。

固然你也能夠不使用 cookie,你能夠經過重寫 URL 地址的方式來實現。它的原理是將用戶的 seesion id 寫入到 URL 中,當瀏覽器解析新的 URL 時就能夠定位到是哪位用戶。

萬變不離其宗,兩種方式都是要保證用戶信息以某種形式保存到客戶端。更先進的 localStorage,sessionStorage,IndexedDB 也是一樣的道理,這裏不去細說。

相關文章
相關標籤/搜索