什麼是cookie,什麼是session
更多內容關注公眾號:SAP Technical
cookie產生背景
由於HTTP協議是無狀態的,而伺服器端的業務必須是要有狀態的。Cookie誕生的最初目的是為了儲存web中的狀態資訊,以方便伺服器端使用。比如判斷使用者是否是第一次訪問網站
cookie
- Cookie是客戶端技術,程式把每個使用者的資料以cookie的形式寫給使用者各自的瀏覽器。當使用者使用瀏覽器再去訪問伺服器中的web資源時,就會帶著各自的資料去。這樣,web資源處理的就是使用者各自的資料了。
- cookie的處理:
- 伺服器像客戶端傳送cookie
- 瀏覽器將cookie儲存
- 之後每次http請求瀏覽器都會將cookie傳送給伺服器端
- Java提供的操作Cookie的API
Java中的javax.servlet.http.Cookie類用於建立一個Cookie
方法 | 型別 | 描述 |
---|---|---|
Cookie(String name,String value) | 構造方法 | 例項化Cookie物件,傳入cooke名稱和cookie的值 |
public String getName() | 普通方法 | 取得Cookie的名字 |
public String getValue() | 普通方法 | 取得Cookie的值 |
public void setValue(String newvalue) | 普通方法 | 設定Cookie的值 |
public void setMaxAge(int expiry) | 普通方法 | 設定Cookie的最大儲存時間,即cookie的有效期,當伺服器給瀏覽器回送一個cookie時,如果在伺服器端沒有呼叫setMaxAge方法設定cookie的有效期,那麼cookie的有效期只在一次會話過程中有效,使用者開一個瀏覽器,點選多個超連結,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一次會話,當使用者關閉瀏覽器,會話就結束了,此時cookie就會失效,如果在伺服器端使用setMaxAge方法設定了cookie的有效期,比如設定了30分鐘,那麼當伺服器把cookie傳送給瀏覽器時,此時cookie就會在客戶端的硬碟上儲存30分鐘,在30分鐘內,即使瀏覽器關了,cookie依然存在,在30分鐘內,開啟瀏覽器訪問伺服器時,瀏覽器都會把cookie一起帶上,這樣就可以在伺服器端獲取到客戶端瀏覽器傳遞過來的cookie裡面的資訊了,這就是cookie設定maxAge和不設定maxAge的區別,不設定maxAge,那麼cookie就只在一次會話中有效,一旦使用者關閉了瀏覽器,那麼cookie就沒有了,那麼瀏覽器是怎麼做到這一點的呢,我們啟動一個瀏覽器,就相當於啟動一個應用程式,而伺服器回送的cookie首先是存在瀏覽器的快取中的,當瀏覽器關閉時,瀏覽器的快取自然就沒有了,所以儲存在快取中的cookie自然就被清掉了,而如果設定了cookie的有效期,那麼瀏覽器在關閉時,就會把快取中的cookie寫到硬碟上儲存起來,這樣cookie就能夠一直存在了。 |
public int getMaxAge() | 普通方法 | 獲取Cookies的有效期 |
public void setPath(String Url) | 普通方法 | 設定cookie的有效路徑,比如把cookie的有效路徑設定為"/xdp",那麼瀏覽器訪問"xdp"目錄下的web資源時,都會帶上cookie,再比如把cookie的有效路徑設定為"/xdp/gacl",那麼瀏覽器只有在訪問"xdp"目錄下的"gacl"這個目錄裡面的web資源時才會帶上cookie一起訪問,而當訪問"xdp"目錄下的web資源時,瀏覽器是不帶cookie的 |
public String getPath() | 普通方法 | 獲取cookie的有效路徑 |
public void setDomain(String pattern) | 普通方法 | 設定cookie的有效域 |
public String getDomain() | 普通方法 | 獲取cookie的有效域 |
response介面也中定義了一個addCookie方法,它用於在其響應頭中增加一個相應的Set-Cookie頭欄位。 同樣,request介面中也定義了一個getCookies方法,它用於獲取客戶端提交的Cookie。
package gac.xdp.cookie;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author gacl
* cookie例項:獲取使用者上一次訪問的時間
*/
public class CookieDemo01 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//設定伺服器端以UTF-8編碼進行輸出
response.setCharacterEncoding("UTF-8");
//設定瀏覽器以UTF-8編碼進行接收,解決中文亂碼問題
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//獲取瀏覽器訪問訪問伺服器時傳遞過來的cookie陣列
Cookie[] cookies = request.getCookies();
//如果使用者是第一次訪問,那麼得到的cookies將是null
if (cookies!=null) {
out.write("您上次訪問的時間是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie.getName().equals("lastAccessTime")) {
Long lastAccessTime =Long.parseLong(cookie.getValue());
Date date = new Date(lastAccessTime);
out.write(date.toLocaleString());
}
}
}else {
out.write("這是您第一次訪問本站!");
}
//使用者訪問過之後重新設定使用者的訪問時間,儲存到cookie中,然後傳送到客戶端瀏覽器
Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis()+"");//建立一個cookie,cookie的名字是lastAccessTime
//將cookie物件新增到response物件中,這樣伺服器在輸出response物件中的內容時就會把cookie也輸出到客戶端瀏覽器
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
session
- session的處理:
- 瀏覽器第一次訪問伺服器,伺服器會建立一個session,並生成一個sessionId
- 將sessionid及對應的session分別作為key和value儲存到快取中,也可以持久化到資料庫中
- 伺服器再把sessionid,以cookie的形式傳送給客戶端
- 瀏覽器下次再訪問時,會直接帶著cookie中的sessionid。然後伺服器根據sessionid找到對應的session進行匹配;
- session常用方法
public void setAttribute(String name,String value)設定指定名字的屬性的值,並將它新增到session會話範圍內,如果這個屬性是會話範圍記憶體在,則更改該屬性的值。
public Object getAttribute(String name)在會話範圍內獲取指定名字的屬性的值,返回值型別為object,如果該屬性不存在,則返回null。
public void removeAttribute(String name),刪除指定名字的session屬性,若該屬性不存在,則出現異常。
public void invalidate(),使session失效。可以立即使當前會話失效,原來會話中儲存的所有物件都不能再被訪問。
public String getId( ),獲取當前的會話ID。每個會話在伺服器端都存在一個唯一的標示sessionID,session物件傳送到瀏覽器的唯一資料就是sessionID,它一般儲存在cookie中。
public void setMaxInactiveInterval(int interval) 設定會話的最大持續時間,單位是秒,負數表明會話永不失效。
public int getMaxInActiveInterval(),獲取會話的最大持續時間。
使用session物件的getCreationTime()和getLastAccessedTime()方法可以獲取會話建立的時間和最後訪問的時間,但其返回值是毫秒,一般需要使用下面的轉換來獲取具體日期和時間。
3.基於session的使用者認證
token(訪問資源的令牌)
1.token處理流程:
- 把使用者的使用者名稱和密碼發到後端
- 後端進行校驗,校驗成功會生成token, 把token傳送給客戶端
-
客戶端自己儲存token, 再次請求就要在Http協議的請求頭中帶著token去訪問服務端,和在服務端儲存的token資訊進行比對校驗。
JWT(json web token)
組成:
一個jwt實際上就是一個字串,它由三部分組成,頭部、載荷與簽名,這三個部分都是json格式。
一、頭部(Header)
頭部用於描述關於該JWT的最基本的資訊,例如其型別以及簽名所用的演算法等。
{
"typ": "JWT",
"alg": "HS256"
}
在這裡,我們說明了這是一個JWT,並且我們所用的簽名演算法是HS256演算法。
二、載荷(Payload)
{
"iss": "John Wu JWT",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "jrocket@example.com",
"from_user": "B",
"target_user": "A"
}
驗證流程:
- 在頭部資訊中宣告加密演算法和常量, 然後把header使用json轉化為字串
- 在載荷中宣告使用者資訊,同時還有一些其他的內容;再次使用json 把載荷部分進行轉化,轉化為字串
- 使用在header中宣告的加密演算法和每個專案隨機生成的secret來進行加密, 把第一步分字串和第二部分的字串進行加密, 生成新的字串。詞字串是獨一無二的。
- 解密的時候,只要客戶端帶著JWT來發起請求,服務端就直接使用secret進行解密。
這裡面的前五個欄位都是由JWT的標準所定義的。
- iss: 該JWT的簽發者
- sub: 該JWT所面向的使用者
- aud: 接收該JWT的一方
- exp(expires): 什麼時候過期,這裡是一個Unix時間戳
- iat(issued at): 在什麼時候簽發的
把頭部和載荷分別進行Base64編碼之後得到兩個字串,然後再將這兩個編碼後的字串用英文句號.連線在一起(頭部在前),形成新的字串:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0
三、簽名(signature)
最後,我們將上面拼接完的字串用HS256演算法進行加密。在加密的時候,我們還需要提供一個金鑰(secret)。加密後的內容也是一個字串,最後這個字串就是簽名,把這個簽名拼接在剛才的字串後面就能得到完整的jwt。header部分和payload部分如果被篡改,由於篡改者不知道金鑰是什麼,也無法生成新的signature部分,服務端也就無法通過,在jwt中,訊息體是透明的,使用簽名可以保證訊息不被篡改。
特點:
- 三部分組成,每一部分都進行字串的轉化
- 解密的時候沒有使用資料庫,僅僅使用的是secret進行解密。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
和session的區別:
基於session和基於jwt的方式的主要區別就是使用者的狀態儲存的位置,session是儲存在服務端的,而jwt是儲存在客戶端的。
- 應用程式分散式部署的情況下,session需要做多機資料共享,通常可以存在資料庫或者redis裡面。而jwt不需要。
- jwt不在服務端儲存任何狀態。RESTful API的原則之一是無狀態,發出請求時,總會返回帶有引數的響應,不會產生附加影響。使用者的認證狀態引入這種附加影響,這破壞了這一原則。另外jwt的載荷中可以儲存一些常用資訊,用於交換資訊,有效地使用 JWT,可以降低伺服器查詢資料庫的次數。
jwt的缺點:
- 安全性
由於jwt的payload是使用base64編碼的,並沒有加密,因此jwt中不能儲存敏感資料。而session的資訊是存在服務端的,相對來說更安全。 - 效能
jwt太長。由於是無狀態使用JWT,所有的資料都被放到JWT裡,如果還要進行一些資料交換,那載荷會更大,經過編碼之後導致jwt非常長,cookie的限制大小一般是4k,cookie很可能放不下,所以jwt一般放在local storage裡面。並且使用者在系統中的每一次http請求都會把jwt攜帶在Header裡面,http請求的Header可能比Body還要大。而sessionId只是很短的一個字串,因此使用jwt的http請求比使用session的開銷大得多。 - 一次性
無狀態是jwt的特點,但也導致了這個問題,jwt是一次性的。想修改裡面的內容,就必須簽發一個新的jwt。
(1)無法廢棄
通過上面jwt的驗證機制可以看出來,一旦簽發一個jwt,在到期之前就會始終有效,無法中途廢棄。例如你在payload中儲存了一些資訊,當資訊需要更新時,則重新簽發一個jwt,但是由於舊的jwt還沒過期,拿著這個舊的jwt依舊可以登入,那登入後服務端從jwt中拿到的資訊就是過時的。為了解決這個問題,我們就需要在服務端部署額外的邏輯,例如設定一個黑名單,一旦簽發了新的jwt,那麼舊的就加入黑名單(比如存到redis裡面),避免被再次使用。
(2)續簽
如果你使用jwt做會話管理,傳統的cookie續簽方案一般都是框架自帶的,session有效期30分鐘,30分鐘內如果有訪問,有效期被重新整理至30分鐘。一樣的道理,要改變jwt的有效時間,就要簽發新的jwt。最簡單的一種方式是每次請求重新整理jwt,即每個http請求都返回一個新的jwt。這個方法不僅暴力不優雅,而且每次請求都要做jwt的加密解密,會帶來效能問題。另一種方法是在redis中單獨為每個jwt設定過期時間,每次訪問時重新整理jwt的過期時間。
可以看出想要破解jwt一次性的特性,就需要在服務端儲存jwt的狀態。但是引入 redis 之後,就把無狀態的jwt硬生生變成了有狀態了,違背了jwt的初衷。而且這個方案和session都差不多了。
基於token的認證方案
相關文章
- cookie是什麼?和session有什麼區別?CookieSession
- Session是什麼?它與Cookie有什麼區別?SessionCookie
- 什麼是Cookie、令牌與JWT?CookieJWT
- 什麼是 cookie 的 httponly 屬性CookieHTTP
- session是什麼時候建立的Session
- session 和 cookie 有什麼區別?SessionCookie
- cookie和session 有什麼區別?CookieSession
- 什麼是DNS,什麼是HostsDNS
- 這是什麼這是什麼
- 什麼是分而治之?什麼是WBS?
- 什麼是WebAuthn、FIDO 是什麼?Web
- ###什麼是Linux核心###什麼是MMULinux
- ITIL是什麼意思?ITIL是什麼?
- 網站安全防護 什麼是session安全網站Session
- SNP全稱是什麼? SNP是什麼公司? SNP是什麼意思?
- 人是什麼?人生是什麼?人為什麼會變?
- 什麼是正向代理?什麼是反向代理?
- NLA是什麼?NLA的原理是什麼?
- ftp是什麼,ftp是什麼東西?FTP
- Java是什麼_Java是做什麼的?Java
- 什麼是this
- 為什麼說session依賴cookie,以及cookie的常用知識SessionCookie
- Redis分散式Session和普通的cookie session有什麼區別?Redis分散式SessionCookie
- 為什麼要有 Servlet ,什麼是 Servlet 容器,什麼是 Web 容器?ServletWeb
- cookie和session有什麼區別?Python學習!CookieSessionPython
- HTTP協議Cookie和Session有什麼區別HTTP協議CookieSession
- 什麼是API介面,具體是什麼意思?API
- IDFA、IMEI、OAID 是什麼,區別是什麼AI
- DRBD是什麼意思?優缺點是什麼?
- 什麼是SSRF攻擊?SSRF用途是什麼?
- GNU是什麼?和Linux是什麼關係?Linux
- 什麼是塊元素?什麼是行內元素?
- 什麼是Tornado?它的特點是什麼?
- 什麼是框架?為什麼說 Angular 是框架?框架Angular
- 什麼是zoom?它有什麼作用?OOM
- 什麼是NLA,它有什麼用?
- 什麼是Django?有什麼用途?Django
- nginx 是什麼,能幹什麼?Nginx