1. 程式人生 > >看完這篇 Session、Cookie、Token,和麵試官扯皮就沒問題了

看完這篇 Session、Cookie、Token,和麵試官扯皮就沒問題了

![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090920745-1422513552.png) ## 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 的過期時間為瀏覽器會話結束; ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090321438-2032814831.png) 接下來客戶端每次向同一個網站傳送請求時,請求頭都會帶上該 Cookie資訊(包含 sessionId ), 然後,伺服器通過讀取請求頭中的 Cookie 資訊,獲取名稱為 JSESSIONID 的值,得到此次請求的 sessionId。 ### Session 的缺點 Session 機制有個缺點,比如 A 伺服器儲存了 Session,就是做了負載均衡後,假如一段時間內 A 的訪問量激增,會轉發到 B 進行訪問,但是 B 伺服器並沒有儲存 A 的 Session,會導致 Session 的失效。 ### Cookies 是什麼 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090329852-726935682.png) 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 的例子 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090350874-162215808.png) 此標頭告訴客戶端儲存 Cookie 現在,隨著對伺服器的每個新請求,瀏覽器將使用 Cookie 頭將所有以前儲存的 Cookie 傳送回伺服器。 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090358057-1079553368.png) 有兩種型別的 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)`外過期。例如 ```http 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 是一個無狀態的協議。這也就意味著當你訪問某個網頁,然後單擊同一站點上的另一個頁面時,伺服器的`記憶體中`將不會記住你之前的操作。 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090447168-1412892230.png) 因此,如果你登入並訪問了你有權訪問的另一個頁面,由於 HTTP 不會記錄你剛剛登入的資訊,因此你將再次登入。 **JWT 和 Session Cookies 就是用來處理在不同頁面之間切換,儲存使用者登入資訊的機制**。 也就是說,這兩種技術都是用來儲存你的登入狀態,能夠讓你在瀏覽任意受密碼保護的網站。通過在每次產生新的請求時對使用者資料進行身份驗證來解決此問題。 所以 JWT 和 Session Cookies 的相同之處是什麼?那就是它們能夠支援你在傳送不同請求之間,記錄並驗證你的登入狀態的一種機制。 ### 什麼是 Session Cookies Session Cookies 也稱為`會話 Cookies`,在 Session Cookies 中,使用者的登入狀態會儲存在`伺服器`的`記憶體`中。當用戶登入時,Session 就被服務端安全的建立。 在每次請求時,伺服器都會從會話 Cookie 中讀取 SessionId,如果服務端的資料和讀取的 SessionId 相同,那麼伺服器就會發送響應給瀏覽器,允許使用者登入。 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090456816-1567261814.png) ### 什麼是 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 組成會是下面這樣 ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090510532-1017074382.png) 然後我們分別對不同的部分進行探討。 **Header** Header 是 JWT 的標頭,它通常由兩部分組成:`令牌的型別(即 JWT) `和使用的 `簽名演算法`,例如 HMAC SHA256 或 RSA。 例如 ```json { "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 宣告`:自定義宣告,旨在在同意使用它們的各方之間共享資訊,既不是註冊宣告也不是公共宣告。 例如 ```json { "sub": "1234567890", "name": "John Doe", "admin": true } ``` 然後 payload Json 塊會被`Base64Url` 編碼形成 JWT 的第二部分。 **signature** JWT 的第三部分是一個簽證資訊,這個簽證資訊由三部分組成 - header (base64後的) - payload (base64後的) - secret 比如我們需要 HMAC SHA256 演算法進行簽名 ```json HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) ``` 簽名用於驗證訊息在此過程中沒有更改,並且對於使用私鑰進行簽名的令牌,它還可以驗證 JWT 的傳送者的真實身份 #### 拼湊在一起 現在我們把上面的三個由點分隔的 Base64-URL 字串部分組成在一起,這個字串可以在 HTML 和 HTTP 環境中輕鬆傳遞這些字串。 下面是一個完整的 JWT 示例,它對 header 和 payload 進行編碼,然後使用 signature 進行簽名 ```json eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ ``` ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090523721-51310429.png) 如果想自己測試編寫的話,可以訪問 JWT 官網 https://jwt.io/#debugger-io ### 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 顯然更適合。 ## 後記 前兩天面試的時候問到了這個題,所以寫篇文章總結一下,還問到了一個面試題,**禁用 Cookies,如何使用 Session** ?網上百度了一下,發現這是 PHP 的面試題...... ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090536271-79379471.png) 但還是選擇瞭解了一下,如何禁用 Cookies 後,使用 Session * 如果禁用了 Cookies,伺服器仍會將 sessionId 以 cookie 的方式傳送給瀏覽器,但是,瀏覽器不再儲存這個cookie (即sessionId) 了。 * 如果想要繼續使用 session,需要採用 `URL 重寫` 的方式來實現,可以參考 https://www.cnblogs.com/Renyi-Fan/p/11012086.html 相關參考: 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/ ![](https://img2020.cnblogs.com/blog/1515111/202004/1515111-20200405090605799-2074553394.png)