Cookie&Session
背景:Cookie和Session的原理、作用及如何設定和相關面試。
一、誕生背景
HTTP是無狀態的,即伺服器無法知道兩個請求是否來自同一個瀏覽器,也就是伺服器不知道使用者上一次做了什麼,每次請求都是完全獨立的。
早期網際網路只是用於簡單的瀏覽文件資訊、檢視黃頁和入口網站等,並沒有互動這個概念。但是隨著網際網路慢慢發展,寬頻、伺服器等硬體設施得到了很多的提升,網際網路允許人們做更多的事情,所以互動式Web(互動式Web即客戶端與伺服器可以互動,如使用者登入、商品購買和論壇等)慢慢就興起了,而HTTP無狀態的特點對此造成了嚴重阻礙。
由於不能記錄使用者上次的操作,偉大的程式設計師發明了隱藏域用於記錄使用者上一次的操作資訊;通過隱藏域把使用者上次操作記錄放在form表單的input中,這樣請求時將表單提交就可以知道上一次使用者的操作了,但是這樣每次都得常見隱藏域而且需要賦值,既麻煩又容易出錯;但是隱藏域作用強大,時至今日都有很多人在用它解決各種問題。隱藏域的寫法如下:
<input type="hidden" name="field_name" value="value">
網景公司的盧-蒙特利Lou Montulli,在1994年將Cookies的概念應用於網路通訊,用於解決使用者網上購物的購物車歷史記錄,而當時最強大的瀏覽器也是網景瀏覽器;之後在網景瀏覽器的支援下其他瀏覽器也逐漸開始支援Cookie,到如今所有瀏覽器都支援Cookie了。
二、什麼是Cookie
Cookie的誕生是為了解決HTTP無狀態的特性,用於滿足互動式Web。
圖1. Chrome瀏覽器百度首頁Cookies
圖2. Firefox瀏覽器百度首頁Cookie
圖3. Safari瀏覽器百度首頁Cookie
上圖中可以看到在Chrome、Firefox和Safari瀏覽器中百度首頁的Cookie,在表格中,每一行都代表著一個Cookie。Cookie是由伺服器發給客戶端的特殊資訊,而這些資訊以文字檔案的形式儲存在客戶端,然後客戶端每次向伺服器傳送請求的時候都會帶上這些特殊的資訊,用於伺服器記錄客戶端的狀態。
Cookie主要運用於一下三個方面:
1、會話狀態管理,如使用者登入狀態、購物車、遊戲分數或其他需要記錄的資訊;
2、個性化設定,如使用者自定義設定、主題等;
3、瀏覽器行為跟蹤。
三、Cookie原理
Cookie是由伺服器發出儲存在瀏覽器的特殊資訊,其具體的過程可以通過一個使用者登入的例子來了解。
圖4. Cookie工作原理
如上圖所示,使用者在輸入使用者名稱和密碼之後,瀏覽器將使用者名稱和密碼傳送給伺服器,伺服器進行驗證,驗證通過後將使用者資訊加密後封裝成Cookie放在請求頭中返回給瀏覽器。
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: user_cookie=Rg3vHJZnehYLjVg7qi3bZjzg; Expires=Tue, 15 Aug 2019 21:47:38 GMT; Path=/; Domain=.169it.com; HttpOnly
[響應體]
瀏覽器收到伺服器返回的資料,發現請求頭中有一個:Set-Cookie,然後它就把這個Cookie儲存起來,下次瀏覽器再請求伺服器的時候,會把Cookie也一起放在請求頭中傳給伺服器。
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: user_cookie=Rg3vHJZnehYLjVg7qi3bZjzg
伺服器收到請求後從請求頭中拿到Cookie,然後解析並得到使用者資訊,說明此使用者已登入,因此Cookie是將資料儲存在客戶端的。
從上述使用者登入的例子可以看出,使用者資訊是儲存在Cookie中,也就相當於是儲存在瀏覽器中的,那麼使用者就可以隨意更改使用者資訊,這是一種不安全的策略。另外,Cookie無論是伺服器傳送給瀏覽器,還是瀏覽器傳送給伺服器,都是放在請求頭中的。
四、Cookie屬性
從上圖的Chorme、Firefox和Safari瀏覽器可以看到一個Cookie有:Name、Value、Domian、Path、Expires/Max-Age、Size、Http(Httponly)和Secure這些屬性。
1、Name & Value
Name表示Cookie的名稱,伺服器就是通過name屬性來獲取某個Cookie的值。
Value表示Cookie的值,多數情況下伺服器會把這個value當做一個Key去快取中查詢儲存的資料。
2、Domain & Path
Domian表示可以訪問此Cookie的域名,下圖我們以百度貼吧首頁的Cookie來了解下Domain的屬性。
圖5. Chrome瀏覽器貼吧首頁Cookie's Domain
圖中可以看出,第三列的Domian有:.baidu.com頂級域名和.teiba.baidu.com二級域名;所以這裡就有一個訪問規則:頂級域名只能設定或訪問頂級域名的Cookie,二級以下的域名只能訪問或設定自身或者頂級域名的Cookie,所以如果要在多個二級域名中共享Cookie的話,只能將Domain的屬性設定為頂級域名。
Path表示可以訪問此Cookie的頁面路徑;如path=/test,那麼只有/test路徑下的頁面可以讀取此Cookie。
3、Expire/Max-Age
Expire/Max-Age表示此cookie的超時時間;若設定其值為一個時間,那麼當到達此時間後,此cookie則會失效;不設定的話預設值是Session,意思是cookie會和session一起失效;當瀏覽器關閉(關閉整個瀏覽器,而不是瀏覽器的標籤頁)後,此cookie失效。另外,當Cookie的過期時間被設定時,設定的日期和時間只與客戶端相關,與服務端無關。
4、Size
Size表示Cookie的name+value的字元數,比如有一個Cookie:id=666,那麼Size=2+3=5。各個瀏覽器對Cookie的支援都有所不同,如下圖:
圖6. 各瀏覽器Cookie支援的個數
5、HTTP
HTTP表示cookie的httponly屬性;若此屬性為true,則只有在http請求頭中會帶有此cookie的資訊,而不能通過document.cookie來訪問此cookie。這麼設計是為了提供一個安全措施來幫助阻止通過JavaScript發起的跨站指令碼攻擊(XXS)竊取cookie的惡劣行為。
圖7. document.cookie
6、Secure
Secure表示是否只能通過https來傳遞此條cookie;不像其他選項,該選項只是一個標記並且沒有其他的值。
五、Java操作Cookie
1、生成Cookie
1 package com.ausclouds.bdbsec.auth.cmb;
2
3 import javax.servlet.http.Cookie;
4 import javax.servlet.http.HttpServlet;
5 import javax.servlet.http.HttpServletRequest;
6 import javax.servlet.http.HttpServletResponse;
7
8 public class CookieServlet extends HttpServlet {
9
10 @Override
11 protected void service(HttpServletRequest req, HttpServletResponse resp){
12 //建立Cookie物件
13 Cookie comCookie = new Cookie("computer", "HP");
14 //伺服器把cookie響應給客戶端,所有的cookie物件,都會在伺服器端建立,通過http響應給客戶端(瀏覽器)
15
16 //如果不設定使用時間,則取不到Cookie的值
17 comCookie.setMaxAge(60*60*24*30);
18
19 //一旦設定了cookie的路徑,就只能通過這一個路徑才能獲取到cookie的資訊
20 comCookie.setPath(req.getContextPath() + "/getCookie.sxt");
21
22 //新增cookie
23 resp.addCookie(comCookie);
24
25 }
26 }
2、獲取Cookie
1 package com.ausclouds.bdbsec.auth.cmb;
2
3 import javax.servlet.http.Cookie;
4 import javax.servlet.http.HttpServlet;
5 import javax.servlet.http.HttpServletRequest;
6 import javax.servlet.http.HttpServletResponse;
7
8 public class GetCookieServlet extends HttpServlet {
9
10 @Override
11 protected void service(HttpServletRequest req, HttpServletResponse resp){
12 //獲取cookie資訊
13 Cookie[] cookies = req.getCookies();
14 for (int i = 0; i<cookies.length; i++){
15 System.out.println(cookies[i].getName() + ":" + cookies[i].getValue());
16 }
17 }
18
19 }
3、刪除Cookie
//刪除Cookie的思路就是替換原來的cookie,並設定它的生存時間為0
Cookie cookie = new Cookie("Cookie",null);//cookie名字要相同
cookie.setMaxAge(0); //
cookie.setPath(request.getContextPath()); // 相同路徑
response.addCookie(cookie);
六、Session
1、誕生背景
其實設計Cookie之初,它並不是僅僅儲存了一個key值,而是直接儲存使用者的資訊,但是由於cookie是存在客戶端的,而且本身儲存的尺寸大小也是有限的,最關鍵的是使用者是可見的,並且可以隨意地修改,這相當地不安全。為了既安全又方便的讀取全域性資訊,於是誕生了Session這種新的儲存會話機制。
2、什麼是Session
Session翻譯為會話,伺服器為每個瀏覽器建立一個會話物件,瀏覽器在第一次請求伺服器時,伺服器便會為該瀏覽器生成一個Seesion物件,儲存在服務端,並且把Session的Id以cookie的形式傳送給客戶端瀏覽器,最終以使用者顯示結束或session超時為結束。
Session工作原理:
1.當某個使用者向伺服器傳送第一個請求時,伺服器為其建立一個sesion,併為此session建立一個標識號(sessionID);
2.這個使用者隨後的所有請求都應包括這個標識號(sessionID),伺服器會校對這個標識號以判斷請求是屬於哪個session的;
3.sessionID標識號有兩種實現方式:Cookie和URL重寫;
4.Cookie是將資料直接儲存在客戶端,而Session是將資料儲存在服務端,所以Session的安全性更佳。
圖8. Session工作原理(基於Cookie實現)
3、Java操作Session
1.建立Session
ActionContext actionContext = ActionContext.getContext();
Map<String, Object> mapSession = actionContext.getSession();
mapSession.put("branch", branch);
mapSession.put("permission", per);
2.JSP獲取Session
1 if(session.getAttribute("branch") == null||session.getAttribute("permission") == null)
2 {
3 response.setCharacterEncoding("utf-8");
4 out.print("<script>alert('您還沒有登入,請登入') </script>");
5 out.flush();
6 out.close();
7 }
3.Java後臺獲取Session
1 ActionContext actionContext = ActionContext.getContext();
2 Map session = actionContext.getSession();
3 String inputUserid =(String)session.get("username");
4 String proving =(String)session.get("proving");
七、面試相關
1、Cookie和Session的關係?
1. 二者都是為實現客戶端與服務端互動而服務的;
2. Cookie是儲存在客戶端,缺點易偽造、不安全;
3. Session是儲存在服務端,會消耗伺服器資源;
4. Session實現有兩種方式:Cookie和URL重寫。
2、Cookie帶來的安全性問題?
1. 會話劫持和XSS:在Web應用中,Cookie常用來標記使用者或授權會話。因此,如果Web應用的Cookie被竊取,可能導致授權使用者的會話受到攻擊;常用的竊取Cookie的方式有社會工程學攻擊和應用程式漏洞進行XSS攻擊;
2. 跨站請求偽造(CSRF):維基百科已經給出了一個較好的CSRF例子。如在不安全的聊天室或論壇上的一張圖片,它實際上是一個給你銀行伺服器傳送體現的請求:
<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">
當你點選開啟該圖片時,如果之前已經登入過你的銀行賬號並且Cookie仍未失效,那麼你銀行裡的錢很可能會被自動轉走;解決CSRF的辦法有:隱藏域驗證碼、確認機制和設定較短的Cookie生命週期等。
3、Session應用場景?
Session主要是伺服器端儲存,用來描述一些使用者資訊或者相關的其他資料,還可以是其他型別的資料,只要是你的業務覺得可以繫結到使用者或客戶端的相關資料都可以放到session中;最基本的場景就是儲存登入使用者資訊。
4、Session生命週期?
1、建立:若訪問的第一個資源是JSP頁面,則建立session物件;若訪問的第一個資源是Servlet,則需要手動呼叫request.getSession()方法來建立session物件;
2、銷燬:呼叫session.invalidate()方法來銷燬session()物件,session會話超時預設30分鐘。