Session、Cookie、Token 【淺談三者之間的那點事】
Cookie 和 Session
HTTP 協議是一種無狀態協議
,即每次服務端接收到客戶端的請求時,都是一個全新的請求,伺服器並不知道客戶端的歷史請求記錄;Session 和 Cookie 的主要目的就是為了彌補 HTTP 的無狀態特性。
Session 是什麼
客戶端請求服務端,服務端會為這次請求開闢一塊記憶體空間
,這個對象便是 Session 對象,存儲結構為 ConcurrentHashMap
。Session 彌補了 HTTP 無狀態特性,伺服器可以利用 Session 存儲客戶端在同一個會話期間的一些操作記錄。
Session 如何判斷是否是同一會話
伺服器第一次接收到請求時,開闢了一塊 Session 空間(創建了Session對象),同時生成一個 sessionId ,並通過響應頭的 **Set-Cookie:JSESSIONID=XXXXXXX **命令,向客戶端發送要求設置 Cookie 的響應; 客戶端收到響應後,在本機客戶端設置了一個 **JSESSIONID=XXXXXXX **的 Cookie 資訊,該 Cookie 的過期時間為瀏覽器會話結束;
接下來客戶端每次向同一個網站發送請求時,請求頭都會帶上該 Cookie資訊(包含 sessionId ), 然後,伺服器通過讀取請求頭中的 Cookie 資訊,獲取名稱為 JSESSIONID 的值,得到此次請求的 sessionId。
Session 的缺點
Session 機制有個缺點,比如 A 伺服器存儲了 Session,就是做了負載均衡後,假如一段時間內 A 的訪問量激增,會轉發到 B 進行訪問,但是 B 伺服器並沒有存儲 A 的 Session,會導致 Session 的失效。
Cookies 是什麼
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 的例子
此標頭告訴客戶端存儲 Cookie
現在,隨著對伺服器的每個新請求,瀏覽器將使用 Cookie 頭將所有以前存儲的 Cookie 發送回伺服器。
有兩種類型的 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 是一個無狀態的協議。這也就意味著當你訪問某個網頁,然後單擊同一站點上的另一個頁面時,伺服器的記憶體中
將不會記住你之前的操作。
因此,如果你登錄並訪問了你有權訪問的另一個頁面,由於 HTTP 不會記錄你剛剛登錄的資訊,因此你將再次登錄。
JWT 和 Session Cookies 就是用來處理在不同頁面之間切換,保存用戶登錄資訊的機制。
也就是說,這兩種技術都是用來保存你的登錄狀態,能夠讓你在瀏覽任意受密碼保護的網站。通過在每次產生新的請求時對用戶數據進行身份驗證來解決此問題。
所以 JWT 和 Session Cookies 的相同之處是什麼?那就是它們能夠支援你在發送不同請求之間,記錄並驗證你的登錄狀態的一種機制。
什麼是 Session Cookies
Session Cookies 也稱為會話 Cookies
,在 Session Cookies 中,用戶的登錄狀態會保存在伺服器
的記憶體
中。當用戶登錄時,Session 就被服務端安全的創建。
在每次請求時,伺服器都會從會話 Cookie 中讀取 SessionId,如果服務端的數據和讀取的 SessionId 相同,那麼伺服器就會發送響應給瀏覽器,允許用戶登錄。
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
- 1)HttpSession介面
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 組成會是下面這樣
然後我們分別對不同的部分進行探討。
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
如果想自己測試編寫的話,可以訪問 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 顯然更適合。
相關參考
//www.cnblogs.com/Renyi-Fan/p/11012086.html
//blog.csdn.net/qq_28296925/article/details/80921585
//www.cnblogs.com/-ROCKS/p/6108556.html
//www.allaboutcookies.org/manage-cookies/
//www.jianshu.com/p/4a124a10fcaf
//tools.ietf.org/html/rfc7519
//jwt.io/introduction/
//wp-rocket.me/blog/browser-cache-vs-cookies-difference/
//wp-rocket.me/blog/difference-json-web-tokens-vs-session-cookies/
關注、留言,我們一起學習,您的收藏是我持續更新的動力!
===============Talk is cheap, show me the code,bye-bye================