Session、Cookie、Token 【淺談三者之間的那點事】

Talent、茂ღ茂 發表於 2020-09-22

Session

Cookie 和 Session

HTTP 協議是一種無狀態協議,即每次服務端接收到客戶端的請求時,都是一個全新的請求,伺服器並不知道客戶端的歷史請求記錄;Session 和 Cookie 的主要目的就是為了彌補 HTTP 的無狀態特性。

Session

Session 是什麼

客戶端請求服務端,服務端會為這次請求開闢一塊記憶體空間,這個物件便是 Session 物件,儲存結構為 ConcurrentHashMap。Session 彌補了 HTTP 無狀態特性,伺服器可以利用 Session 儲存客戶端在同一個會話期間的一些操作記錄。

Session 如何判斷是否是同一會話

伺服器第一次接收到請求時,開闢了一塊 Session 空間(建立了Session物件),同時生成一個 sessionId ,並通過響應頭的 **Set-Cookie:JSESSIONID=XXXXXXX **命令,向客戶端傳送要求設定 Cookie 的響應; 客戶端收到響應後,在本機客戶端設定了一個 **JSESSIONID=XXXXXXX **的 Cookie 資訊,該 Cookie 的過期時間為瀏覽器會話結束;

Session

接下來客戶端每次向同一個網站傳送請求時,請求頭都會帶上該 Cookie資訊(包含 sessionId ), 然後,伺服器通過讀取請求頭中的 Cookie 資訊,獲取名稱為 JSESSIONID 的值,得到此次請求的 sessionId。

Session 的缺點

Session 機制有個缺點,比如 A 伺服器儲存了 Session,就是做了負載均衡後,假如一段時間內 A 的訪問量激增,會轉發到 B 進行訪問,但是 B 伺服器並沒有儲存 A 的 Session,會導致 Session 的失效。

Cookies 是什麼

Session

HTTP 協議中的 Cookie 包括 Web Cookie 和瀏覽器 Cookie,它是伺服器傳送到 Web 瀏覽器的一小塊資料。伺服器傳送到瀏覽器的 Cookie,瀏覽器會進行儲存,並與下一個請求一起傳送到伺服器。通常,它用於判斷兩個請求是否來自於同一個瀏覽器,例如使用者保持登入狀態。

  • HTTP Cookie 機制是 HTTP 協議無狀態的一種補充和改良

Cookie 主要用於下面三個目的

  • 會話管理

登陸、購物車、遊戲得分或者伺服器應該記住的其他內容

  • 個性化

使用者偏好、主題或者其他設定

  • 追蹤

記錄和分析使用者行為

Cookie 曾經用於一般的客戶端儲存。雖然這是合法的,因為它們是在客戶端上儲存資料的唯一方法,但如今建議使用現代儲存 API。Cookie 隨每個請求一起傳送,因此它們可能會降低效能(尤其是對於移動資料連線而言)。

建立 Cookie

當接收到客戶端發出的 HTTP 請求時,伺服器可以傳送帶有響應的 Set-Cookie 標頭,Cookie 通常由瀏覽器儲存,然後將 Cookie 與 HTTP 標頭一同向伺服器發出請求。

Set-Cookie 和 Cookie 標頭

Set-Cookie HTTP 響應標頭將 cookie 從伺服器傳送到使用者代理。下面是一個傳送 Cookie 的例子

Session 

此標頭告訴客戶端儲存 Cookie

現在,隨著對伺服器的每個新請求,瀏覽器將使用 Cookie 頭將所有以前儲存的 Cookie 傳送回伺服器。

Session

有兩種型別的 Cookies,一種是 Session Cookies,一種是 Persistent Cookies,如果 Cookie 不包含到期日期,則將其視為會話 Cookie。會話 Cookie 儲存在記憶體中,永遠不會寫入磁碟,當瀏覽器關閉時,此後 Cookie 將永久丟失。如果 Cookie 包含有效期 ,則將其視為永續性 Cookie。在到期指定的日期,Cookie 將從磁碟中刪除。

還有一種是 Cookie的 Secure 和 HttpOnly 標記,下面依次來介紹一下

會話 Cookies

上面的示例建立的是會話 Cookie ,會話 Cookie 有個特徵,客戶端關閉時 Cookie 會刪除,因為它沒有指定Expires或 Max-Age 指令。

但是,Web 瀏覽器可能會使用會話還原,這會使大多數會話 Cookie 保持永久狀態,就像從未關閉過瀏覽器一樣。

永久性 Cookies

永久性 Cookie 不會在客戶端關閉時過期,而是在特定日期(Expires)特定時間長度(Max-Age)外過期。例如

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

Cookie 的 Secure 和 HttpOnly 標記

安全的 Cookie 需要經過 HTTPS 協議通過加密的方式傳送到伺服器。即使是安全的,也不應該將敏感資訊儲存在cookie 中,因為它們本質上是不安全的,並且此標誌不能提供真正的保護。

HttpOnly 的作用

  • 會話 Cookie 中缺少 HttpOnly 屬性會導致攻擊者可以通過程式(JS指令碼、Applet等)獲取到使用者的 Cookie 資訊,造成使用者 Cookie 資訊洩露,增加攻擊者的跨站指令碼攻擊威脅。

  • HttpOnly 是微軟對 Cookie 做的擴充套件,該值指定 Cookie 是否可通過客戶端指令碼訪問。

  • 如果在 Cookie 中沒有設定 HttpOnly 屬性為 true,可能導致 Cookie 被竊取。竊取的 Cookie 可以包含標識站點使用者的敏感資訊,如 ASP.NET 會話 ID 或 Forms 身份驗證票證,攻擊者可以重播竊取的 Cookie,以便偽裝成使用者或獲取敏感資訊,進行跨站指令碼攻擊等。

 

Cookie 的作用域

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

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

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

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

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

 

JSON Web Token 和 Session Cookies 的對比

JSON Web Token ,簡稱 JWT,它和 Session都可以為網站提供使用者的身份認證,但是它們不是一回事。

下面是 JWT 和 Session 不同之處的研究

JWT 和 Session Cookies 的相同之處

在探討 JWT 和 Session Cookies 之前,有必要需要先去理解一下它們的相同之處。

它們既可以對使用者進行身份驗證,也可以用來在使用者單擊進入不同頁面時以及登陸網站或應用程式後進行身份驗證。

如果沒有這兩者,那你可能需要在每個頁面切換時都需要進行登入了。因為 HTTP 是一個無狀態的協議。這也就意味著當你訪問某個網頁,然後單擊同一站點上的另一個頁面時,伺服器的記憶體中將不會記住你之前的操作。

Session

因此,如果你登入並訪問了你有權訪問的另一個頁面,由於 HTTP 不會記錄你剛剛登入的資訊,因此你將再次登入。

JWT 和 Session Cookies 就是用來處理在不同頁面之間切換,儲存使用者登入資訊的機制。

也就是說,這兩種技術都是用來儲存你的登入狀態,能夠讓你在瀏覽任意受密碼保護的網站。通過在每次產生新的請求時對使用者資料進行身份驗證來解決此問題。

所以 JWT 和 Session Cookies 的相同之處是什麼?那就是它們能夠支援你在傳送不同請求之間,記錄並驗證你的登入狀態的一種機制。

 

什麼是 Session Cookies

Session Cookies 也稱為會話 Cookies,在 Session Cookies 中,使用者的登入狀態會儲存在伺服器記憶體中。當使用者登入時,Session 就被服務端安全的建立。

在每次請求時,伺服器都會從會話 Cookie 中讀取 SessionId,如果服務端的資料和讀取的 SessionId 相同,那麼伺服器就會傳送響應給瀏覽器,允許使用者登入。

Session

token
令牌,是使用者身份的驗證方式。
最簡單的token組成:uid(使用者唯一的身份標識)、time(當前時間的時間戳)、sign(簽名)。
對Token認證的五點認識

  • 一個Token就是一些資訊的集合;
  • 在Token中包含足夠多的資訊,以便在後續請求中減少查詢資料庫的機率;
  • 服務端需要對cookie和HTTP Authrorization Header進行Token資訊的檢查;
  • 基於上一點,你可以用一套token認證程式碼來面對瀏覽器類客戶端和非瀏覽器類客戶端;
  • 因為token是被簽名的,所以我們可以認為一個可以解碼認證通過的token是由我們系統發放的,其中帶的資訊是合法有效的;

session

  • 會話,代表伺服器與瀏覽器的一次會話過程,這個過程是連續的,也可以時斷時續。
  • cookie中存放著一個sessionID,請求時會傳送這個ID;
  • session因為請求(request物件)而產生;
  • session是一個容器,可以存放會話過程中的任何物件;
  • session的建立與使用總是在服務端,瀏覽器從來都沒有得到過session物件;
  • session是一種http儲存機制,目的是為武裝的http提供持久機制。

cookie

儲存在使用者本地終端上的資料,伺服器生成,傳送給瀏覽器,下次請求統一網站給伺服器。

cookie與session區別
cookie資料存放在客戶端上,session資料放在伺服器上;
cookie不是很安全,且儲存資料有限;
session一定時間內儲存在伺服器上,當訪問增多,佔用伺服器效能。

session與token
作為身份認證,token安全行比session好;
Session 認證只是簡單的把User 資訊儲存到Session 裡,因為SID 的不可預測性,暫且認為是安全的。這是一種認證手段。 而Token ,如果指的是OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對使用者,授權是針對App 。其目的是讓 某App有權利訪問 某使用者 的資訊。

token與cookie
Cookie是不允許垮域訪問的,但是token是支援的, 前提是傳輸的使用者認證資訊通過HTTP頭傳輸;

token就是令牌,比如你授權(登入)一個程式時,他就是個依據,判斷你是否已經授權該軟體;cookie就是寫在客戶端的一個txt檔案,裡面包括你登入資訊之類的,這樣你下次在登入某個網站,就會自動呼叫cookie自動登入使用者名稱;session和cookie差不多,只是session是寫在伺服器端的檔案,也需要在客戶端寫入cookie檔案,但是檔案裡是你的瀏覽器編號.Session的狀態是儲存在伺服器端,客戶端只有session id;而Token的狀態是儲存在客戶端。

HTTP協議與狀態保持:Http是一個無狀態協議 

  • 1. 實現狀態保持的方案:
    • 1)修改Http協議,使得它支援狀態保持(難做到)
    • 2)Cookies:通過客戶端來保持狀態資訊
    • Cookie是伺服器發給客戶端的特殊資訊
    • cookie是以文字的方式儲存在客戶端,每次請求時都帶上它
    • 3)Session:通過伺服器端來保持狀態資訊
    • Session是伺服器和客戶端之間的一系列的互動動作
    • 伺服器為每個客戶端開闢記憶體空間,從而保持狀態資訊
    • 由於需要客戶端也要持有一個標識(id),因此,也要求伺服器端和客戶端傳輸該標識,
    • 標識(id)可以藉助Cookie機制或者其他的途徑來儲存
  • 2. COOKIE機制
    • 1)Cookie的基本特點
    • Cookie儲存在客戶端
    • 只能儲存字串物件,不能儲存物件型別
    • 需要客戶端瀏覽器的支援:客戶端可以不支援,瀏覽器使用者可能會禁用Cookie
    • 2)採用Cookie需要解決的問題
  • Cookie的建立
    • 通常是在伺服器端建立的(當然也可以通過javascript來建立)
    • 伺服器通過在http的響應頭加上特殊的指示,那麼瀏覽器在讀取這個指示後就會生成相應的cookie了
  • Cookie存放的內容
    • 業務資訊("key","value")
    • 過期時間
    • 域和路徑
    • 瀏覽器是如何通過Cookie和伺服器通訊?
    • 通過請求與響應,cookie在伺服器和客戶端之間傳遞
    • 每次請求和響應都把cookie資訊載入到響應頭中;依靠cookie的key傳遞。
  • 3. COOKIE程式設計
    • 1)Cookie類  
    • Servlet API封裝了一個類:javax.servlet.http.Cookie,封裝了對Cookie的操作,包括:   
public Cookie(String name, String value) //構造方法,用來建立一個Cookie
HttpServletRequest.getCookies() //從Http請求中可以獲取Cookies
HttpServletResponse.addCookie(Cookie) //往Http響應新增Cookie
public int getMaxAge() //獲取Cookie的過期時間值
public void setMaxAge(int expiry) //設定Cookie的過期時間值
  • 2)Cookie的建立
    • Cookie是一個名值對(key=value),而且不管是key還是value都是字串  
如: Cookie visit = new Cookie("visit", "1");
  • 3)Cookie的型別——過期時間
    • 會話Cookie  
    • Cookie.setMaxAge(-1);//負整數  
    • 儲存在瀏覽器的記憶體中,也就是說關閉了瀏覽器,cookie就會丟失  
    • 普通cookie  
    • Cookie.setMaxAge(60);//正整數,單位是秒  
    • 表示瀏覽器在1分鐘內不繼續訪問伺服器,Cookie就會被過時失效並銷燬(通常儲存在檔案中)  

注意:

cookie.setMaxAge(0);//等價於不支援Cookie;
  • 4. SESSION機制
    • 每次客戶端傳送請求,服務斷都檢查是否含有sessionId。  
    • 如果有,則根據sessionId檢索出session並處理;如果沒有,則建立一個session,並繫結一個不重複的sessionId。  
    • 1)基本特點  
      • 狀態資訊儲存在伺服器端。這意味著安全性更高    
      • 通過類似與Hashtable的資料結構來儲存    
      • 能支援任何型別的物件(session中可含有多個物件)    
    • 2)儲存會話id的技術(1)  
    • Cookie  
      • 這是預設的方式,在客戶端與伺服器端傳遞JSeesionId    
      • 缺點:客戶端可能禁用Cookie    
      • 表單隱藏欄位    
      • 在被傳遞迴客戶端之前,在 form 裡面加入一個hidden域,設定JSeesionId:    
<input type=hidden name=jsessionid value="3948E432F90932A549D34532EE2394" />
  • URL重寫
    • 直接在URL後附加上session id的資訊  
    • HttpServletResponse物件中,提供瞭如下的方法:  
encodeURL(url); //url為相對路徑
  • 5. SESSION程式設計
    • 1)HttpSession介面  
      • Servlet API定義了介面:javax.servlet.http.HttpSession, Servlet容器必須實現它,用以跟蹤狀態。    
      • 當瀏覽器與Servlet容器建立一個http會話時,容器就會通過此介面自動產生一個HttpSession物件    
    • 2)獲取Session   
HttpServletRequest物件獲取session,返回HttpSession:
request.getSession(); # 表示如果session物件不存在,就建立一個新的會話
request.getSession(true); # 等價於上面這句;如果session物件不存在,就建立一個新的會話
request.getSession(false); # 表示如果session物件不存在就返回 null,不會建立新的會話物件
  • 3)Session存取資訊
session.setAttribute(String name,Object o) # 往session中儲存資訊
Object session.getAttribute(String name) # 從session物件中根據名字獲取資訊
  • 4)設定Session的有效時間
    • public void setMaxInactiveInterval(int interval)  
    • 設定最大非活動時間間隔,單位秒;  
    • 如果引數interval是負值,表示永不過時。零則是不支援session。  
    • 通過配置web.xml來設定會話超時,單位是分鐘  
<seesion-config>
<session-timeout>1</session-timeout>
</session-config>

允許兩種方式並存,但前者優先順序更高

  • 5)其他常用的API
HttpSession.invalidate() # 手工銷燬Session
boolean HttpSession.isNew() # 判斷Session是否新建
如果是true,表示伺服器已經建立了該session,但客戶端還沒有加入(還沒有建立會話的握手)
HttpSession.getId() # 獲取session的id

 

  • 6). 兩種狀態跟蹤機制的比較

Cookie Session

  • 保持在客戶端 儲存在伺服器端
  • 只能保持字串物件 支援各種型別物件
  • 通過過期時間值區分Cookie的型別 需要sessionid來維護與客戶端的通訊
  • 會話Cookie——負數 Cookie(預設)
  • 普通Cookie——正數 表單隱藏欄位
  • 不支援Cookie——0 url重寫

 

什麼是 Json Web Tokens

Json Web Token 的簡稱就是 JWT,通常可以稱為 Json 令牌。它是RFC 7519 中定義的用於安全的將資訊作為 Json 物件進行傳輸的一種形式。JWT 中儲存的資訊是經過數字簽名的,因此可以被信任和理解。可以使用 HMAC 演算法或使用 RSA/ECDSA 的公用/專用金鑰對 JWT 進行簽名。

使用 JWT 主要用來下面兩點

  • 認證(Authorization):這是使用 JWT 最常見的一種情況,一旦使用者登入,後面每個請求都會包含 JWT,從而允許使用者訪問該令牌所允許的路由、服務和資源。單點登入是當今廣泛使用 JWT 的一項功能,因為它的開銷很小。
  • 資訊交換(Information Exchange):JWT 是能夠安全傳輸資訊的一種方式。通過使用公鑰/私鑰對 JWT 進行簽名認證。此外,由於簽名是使用 head 和 payload 計算的,因此你還可以驗證內容是否遭到篡改。

JWT 的格式

下面,我們會探討一下 JWT 的組成和格式是什麼

JWT 主要由三部分組成,每個部分用 . 進行分割,各個部分分別是

  • Header
  • Payload
  • Signature

因此,一個非常簡單的 JWT 組成會是下面這樣

Session

然後我們分別對不同的部分進行探討。

Header

Header 是 JWT 的標頭,它通常由兩部分組成:令牌的型別(即 JWT)和使用的 簽名演算法,例如 HMAC SHA256 或 RSA。

例如

{
  "alg": "HS256",
  "typ": "JWT"
}

 

指定型別和簽名演算法後,Json 塊被 Base64Url 編碼形成 JWT 的第一部分。

Payload

Token 的第二部分是 Payload,Payload 中包含一個宣告。宣告是有關實體(通常是使用者)和其他資料的宣告。共有三種型別的宣告:registered, public 和 private 宣告。

  • registered 宣告: 包含一組建議使用的預定義宣告,主要包括
ISS簽發人
iss (issuer) 簽發人
exp (expiration time) 過期時間
sub (subject) 主題
aud (audience) 受眾
nbf (Not Before) 生效時間
iat (Issued At) 簽發時間
jti (JWT ID) 編號
  • public 宣告:公共的宣告,可以新增任何的資訊,一般新增使用者的相關資訊或其他業務需要的必要資訊,但不建議新增敏感資訊,因為該部分在客戶端可解密。
  • private 宣告:自定義宣告,旨在在同意使用它們的各方之間共享資訊,既不是註冊宣告也不是公共宣告。

例如

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

 

然後 payload Json 塊會被Base64Url 編碼形成 JWT 的第二部分。

signature

JWT 的第三部分是一個簽證資訊,這個簽證資訊由三部分組成

  • header (base64後的)
  • payload (base64後的)
  • secret

比如我們需要 HMAC SHA256 演算法進行簽名

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

 

簽名用於驗證訊息在此過程中沒有更改,並且對於使用私鑰進行簽名的令牌,它還可以驗證 JWT 的傳送者的真實身份

拼湊在一起

現在我們把上面的三個由點分隔的 Base64-URL 字串部分組成在一起,這個字串可以在 HTML 和 HTTP 環境中輕鬆傳遞這些字串。

下面是一個完整的 JWT 示例,它對 header 和 payload 進行編碼,然後使用 signature 進行簽名

 

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

 

Session

如果想自己測試編寫的話,可以訪問 JWT 官網 

JWT 和 Session Cookies 的不同

JWT 和 Session Cookies 都提供安全的使用者身份驗證,但是它們有以下幾點不同

密碼簽名

JWT 具有加密簽名,而 Session Cookies 則沒有。

JSON 是無狀態的

JWT 是無狀態的,因為宣告被儲存在客戶端,而不是服務端記憶體中。

身份驗證可以在本地進行,而不是在請求必須通過伺服器資料庫或類似位置中進行。 這意味著可以對使用者進行多次身份驗證,而無需與站點或應用程式的資料庫進行通訊,也無需在此過程中消耗大量資源。

可擴充套件性

Session Cookies 是儲存在伺服器記憶體中,這就意味著如果網站或者應用很大的情況下會耗費大量的資源。由於 JWT 是無狀態的,在許多情況下,它們可以節省伺服器資源。因此 JWT 要比 Session Cookies 具有更強的可擴充套件性

JWT 支援跨域認證

Session Cookies 只能用在單個節點的域或者它的子域中有效。如果它們嘗試通過第三個節點訪問,就會被禁止。如果你希望自己的網站和其他站點建立安全連線時,這是一個問題。

使用 JWT 可以解決這個問題,使用 JWT 能夠通過多個節點進行使用者認證,也就是我們常說的跨域認證

 

JWT 和 Session Cookies 的選型

我們上面探討了 JWT 和 Cookies 的不同點,相信你也會對選型有了更深的認識,大致來說 

對於只需要登入使用者並訪問儲存在站點資料庫中的一些資訊的中小型網站來說,Session Cookies 通常就能滿足。

如果你有企業級站點,應用程式或附近的站點,並且需要處理大量的請求,尤其是第三方或很多第三方(包括位於不同域的API),則 JWT 顯然更適合。


 

相關參考

https://www.cnblogs.com/Renyi-Fan/p/11012086.html

https://blog.csdn.net/qq_28296925/article/details/80921585

https://www.cnblogs.com/-ROCKS/p/6108556.html

https://www.allaboutcookies.org/manage-cookies/

https://www.jianshu.com/p/4a124a10fcaf

https://tools.ietf.org/html/rfc7519

https://jwt.io/introduction/

https://wp-rocket.me/blog/browser-cache-vs-cookies-difference/

https://wp-rocket.me/blog/difference-json-web-tokens-vs-session-cookies/


Session、Cookie、Token 【淺談三者之間的那點事】

關注、留言,我們一起學習,您的收藏是我持續更新的動力!

 

===============Talk is cheap, show me the code,bye-bye================