詳細總結介紹Get和Post,Session和Cookies,Token和Cookies自登陸的思路

Deft_MKJing宓珂璟發表於2016-12-20

Sessions和Cookies

一、會話機制

Web程式中常用的技術,用來跟蹤使用者的整個會話。常用的會話跟蹤技術是Cookie與Session。Cookie通過在客戶端記錄資訊確定使用者身份Session通過在伺服器端記錄資訊確定使用者身份

一次會話指的是:就好比打電話,A給B打電話,接通之後,會話開始,直到結束通話電話,該次會話就結束了,而瀏覽器訪問伺服器,就跟打電話一樣,瀏覽器A給伺服器傳送請求,訪問web程式,該次會話就已經接通,其中不管瀏覽器傳送多少請求(就相當於接通電話後說話一樣),都視為一次會話,直到瀏覽器關閉,本次會話結束。其中注意,一個瀏覽器就相當於一部電話,如果使用火狐瀏覽器,訪問伺服器,就是一次會話了,然後開啟google瀏覽器,訪問伺服器,這是另一個會話,雖然是在同一臺電腦,同一個使用者在訪問,但是,這是兩次不同的會話。

知道了什麼是會話後,思考一個問題,一個瀏覽器訪問一個伺服器就能建立一個會話,如果別的電腦,都同時訪問該伺服器,就會建立很多會話,就拿一些購物網站來說,我們訪問一個購物網站的伺服器,會話就被建立了,然後就點選瀏覽商品,對感興趣的商品就先加入購物車,等待一起付賬,這看起來是很普通的操作,但是想一下,如果有很多別的電腦上的瀏覽器同時也在訪問該購物網站的伺服器,跟我們做類似的操作呢?伺服器又是怎麼記住使用者,怎麼知道使用者A購買的任何商品都應該放在A的購物車內,不論是使用者A什麼時間購買的,不能放入使用者B或使用者C的購物車內的呢?所以就有了cookie和session這兩個技術,就像第一行說的那樣,cookie和session用來跟蹤使用者的整個會話,

Cookie和Session之間的區別和聯絡

假如一個咖啡店有喝5杯咖啡免費贈一杯咖啡的優惠,然而一次性消費5杯咖啡的機會微乎其微,這時就需要某種方式來紀錄某位顧客的消費數量。想象一下其實也無外乎下面的幾種方案:

1、該店的店員很厲害,能記住每位顧客的消費數量,只要顧客一走進咖啡店,店員就知道該怎麼對待了。這種做法就是協議本身支援狀態。但是http協議本身是無狀態的

2、發給顧客一張卡片,上面記錄著消費的數量,一般還有個有效期限。每次消費時,如果顧客出示這張卡片,則此次消費就會與以前或以後的消費相聯絡起來。這種做法就是在客戶端保持狀態。也就是cookie。 顧客就相當於瀏覽器,cookie如何工作,下面會詳細講解

3、發給顧客一張會員卡,除了卡號之外什麼資訊也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店裡的紀錄本上找到這個卡號對應的紀錄新增一些消費資訊。這種做法就是在伺服器端保持狀態。

由於HTTP協議是無狀態的,而出於種種考慮也不希望使之成為有狀態的,因此,後面兩種方案就成為現實的選擇。具體來說cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在伺服器端保持狀態的方案。同時我們也看到,由於採用伺服器端保持狀態的方案在客戶端也需要儲存一個標識,所以session機制可能需要藉助於cookie機制來達到儲存標識的目的,但實際上它還有其他選擇

 

二、Cookie

上面已經介紹了為什麼要使用Cookie,以及Cookie的一些特點,比如儲存在客戶端,用來記錄使用者身份資訊的,現在來看看如何使用Cookie。

藉著上面會員卡的例子來說,採用的是第二種方案,其中還需要解決的問題就是:如何分發會員卡,會員卡的內容,客戶如何使用會員卡,會員卡的有效日期,會員卡的使用範圍

1、如何分發會員卡、會員卡的內容:也就是cookie是如何建立的?建立後如何傳送給客戶端?

由伺服器進行建立,也就相當於咖啡店來建立會員卡,在建立會員卡的同時,就會將會員卡中的內容也給設了

Cookie cookie = new Cookie(key,value);  //以鍵值對的方式存放內容,

response.addCookie(cookie);  //傳送回瀏覽器端

注意:一旦cookie建立好了,就不能在往其中增加別的鍵值對,但是可以修改其中的內容,

cookie.setValue();  //將key對應的value值修改

2、客戶如何使用會員卡,cookie在客戶端是如何工作的,工作原理是什麼?

 

一般來講很多有以下引數

 

expire 過期時間


path 路徑


domain 域名


secure  它主要是用來設定是否對 cookie 進行加密傳輸,預設為 false,若設定為 ture,則只有在使用 HTTPS 的情況下,這個 cookie 才可以被設定


httponly  置是否只使用 HTTP 訪問cookie,若設定為 true,則客戶端指令碼(如JavaScript)將無法訪問該 cookie,這個引數一定程度上可以降低 XSS 攻擊的風險

這個過程就相當於,咖啡店建立好了會員卡,並且已經設定了其中的內容,交到了客戶手中,下次客戶過來時,就帶著會員卡過來,就知道你是會員了,然後咖啡店就拿到你的會員卡對其進行操作。

set_cookie(key, value='', max_age=None, expires=None):設定Cookie

  • key、value都是字串型別
  • max_age是一個整數,表示在指定秒數後過期
  • expires是一個datetime或timedelta物件,會話將在這個指定的日期/時間過期,注意datetime和timedelta值只有在使用PickleSerializer時才可序列化
  • max_age與expires二選一
  • 如果不指定過期時間,則兩個星期後過期

3.會員卡的使用範圍?

比如星巴克在北京有一個分店,在上海也有一個分店,我們只是在北京的星巴克辦理了會員卡,那麼當我們到上海時,就不能使用該會員卡進行打折優惠了。而cookie也是如此,可以設定伺服器端獲取cookie的訪問路徑,而並非在伺服器端的web專案中所有的servlet都能訪問該cookie。

cookie預設路徑:當前訪問的servlet父路徑。

例如:http://localhost:8080/test01/a/b/c/SendCookieServlet

預設路徑:/test01/a/b/c  也就是說,在該預設路徑下的所有Servlet都能夠獲取到cookie,/test01/a/b/c/MyServlet 這個MyServlet就能獲取到cookie。

修改cookie的訪問路徑

setPath("/");  //在該伺服器下,任何專案,任何位置都能獲取到cookie,

通途:保證在tomcat下所有的web專案可以共享相同的cookie 

例如:tieba , wenku , beike 多個專案共享資料。例如使用者名稱。

setPath("/test01/");  //在test01專案下任何位置都能獲取到cookie。

4、總結Cookie:

工作流程:

  • 1. servlet建立cookie,儲存少量資料,傳送瀏覽器。
  • 2. 瀏覽器獲得伺服器傳送的cookie資料,將自動的儲存到瀏覽器端。
  • 3. 下次訪問時,瀏覽器將自動攜帶cookie資料傳送給伺服器。

cookie操作

  • 1.建立cookie:new Cookie(name,value)
  • 2.傳送cookie到瀏覽器:HttpServletResponse.addCookie(Cookie)
  • 3.servlet接收cookie:HttpServletRequest.getCookies()  瀏覽器傳送的所有cookie

cookie特點

  • 1. 每一個cookie檔案大小:4kb , 如果超過4kb瀏覽器不識別
  • 2. 一個web站點(web專案):傳送20個
  • 3.一個瀏覽器儲存總大小:300個
  • 4.cookie 不安全,可能洩露使用者資訊。瀏覽器支援禁用cookie操作。
  • 5. 預設情況生命週期:與瀏覽器會話一樣,當瀏覽器關閉時cookie銷燬的。---臨時cookie

5.cookie案例

  • 會話狀態管理(如使用者登入狀態、購物車)

  • 個性化設定(如使用者自定義設定)

  • 瀏覽器行為跟蹤(如跟蹤分析使用者行為歷史記錄,使用者名稱)

5.1.記住使用者名稱

登入時,在伺服器端獲取到使用者名稱,然後建立一個cookie,將使用者名稱存入cookie中,傳送回瀏覽器端,然後瀏覽器下次在訪問登入頁面時,先拿到cookie,將cookie中的資訊拿出來,看是否儲存了該使用者名稱,如果儲存了,那麼直接用他,如果沒有,則自己手寫使用者名稱。

5.2.歷史記錄

比如購物網站,都會有我們的瀏覽記錄的,實現原理其實也是用cookie技術,每瀏覽一個商品,就將其存入cookie中,到需要顯示瀏覽記錄時,只需要將cookie拿出來遍歷即可。  

三.session

同樣,會員卡的例子的第三種方法,發給顧客一張會員卡,除了卡號之外什麼資訊也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店裡的紀錄本上找到這個卡號對應的紀錄新增一些消費資訊。這種做法就是在伺服器端保持狀態。 這就是session的用法,在伺服器端來保持狀態,儲存一些使用者資訊。

功能作用:伺服器用於共享資料技術

當瀏覽器訪問伺服器的時候,第一次是沒有cookies的,裡面自然沒有session,因此伺服器懶載入request的session,獲取不到就建立,獲取到就讀取資訊,建立的session的時候會有一個sessionid專門標識這個session,然後跟著cookies,返回給瀏覽器,瀏覽器儲存在本地,每次請求就帶上cookies,由伺服器解析出sessionid,來記錄使用者行為

1.session原理分析:

首先瀏覽器請求伺服器訪問web站點時,程式需要為客戶端的請求建立一個session的時候,伺服器首先會檢查這個客戶端請求是否已經包含了一個session標識、稱為SESSIONID,如果已經包含了一個sessionid則說明以前已經為此客戶端建立過session,伺服器就按照sessionid把這個session檢索出來使用,如果客戶端請求不包含session id,則伺服器為此客戶端建立一個session並且生成一個與此session相關聯的session id,sessionid 的值應該是一個既不會重複,又不容易被找到規律以仿造的字串,這個sessionid將在本次響應中返回到客戶端儲存,儲存這個sessionid的方式就可以是cookie,這樣在互動的過程中,瀏覽器可以自動的按照規則把這個標識發回給伺服器,伺服器根據這個sessionid就可以找得到對應的session,又回到了這段文字的開始。

 

以DJango為例,獲取到session方式為,為什麼用request來獲取,上面已經解釋了,可以理解為OC懶載入,況且DJango中間層攔截會提取cookie資訊,沒有建立,有的話提取,我們只需要直接獲取即可

request.session

 以登入最簡單的POST為例

def login_handle(request):
    request.session['name'] = request.POST['username']
    request.session.set_expiry(0)

    return redirect(reverse('booktest:mainTest'))

2.session的一些小疑問

session就是一個字典物件,只是key可以重複

1.session是什麼時候建立的,誰建立的?

它是由伺服器根據請求頭裡面的Cookies裡面的session資訊,沒有的話就建立出來,繫結一個id,和cookies一起返回到客戶端

2.session怎麼儲存?儲存到哪裡?

以DJango伺服器為例,預設配置是在sqlite3裡面的,如果我們配置成Mysql,那麼就會存入資料庫中的session表中,如果我們配置了Redis,那麼session就會儲存在redis記憶體中,效率就更高,如下圖,左邊是Mysql,右邊是redis,我們本來是存在mysql,可以再表中查出來,現在清掉了,配置成了右邊的redis,可以看到對應的value是base64加密的

可以自己建立出來抓包試試,這裡存的key就是cookies傳遞的sessionid,因此在cookie有效期內或者伺服器的session沒過期之前,都可以通過這個id來進行資料的記錄,實現了使用者行為的記錄

3.session生命週期

常常聽到這樣一種誤解“只要關閉瀏覽器,session就消失了”。其實可以想象一下會員卡的例子,除非顧客主動對店家提出銷卡,否則店家絕對不會輕易刪除顧客的資料。對session來說也是一樣的,除非程式通知伺服器刪除一個session,否則伺服器會一直保留,程式一般都是在使用者做log off的時候發個指令去刪除session。然而瀏覽器從來不會主動在關閉之前通知伺服器它將要關閉,因此伺服器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分session機制都使用會話cookie來儲存session id,而關閉瀏覽器後這個session id就消失了,再次連線伺服器時也就無法找到原來的session。如果伺服器設定的cookie被儲存到硬碟上,或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的session id傳送給伺服器,則再次開啟瀏覽器仍然能夠找到原來的session 

恰恰是由於關閉瀏覽器不會導致session被刪除,迫使伺服器為seesion設定了一個失效時間,一般是30分鐘,當距離客戶端上一次使用session的時間超過這個失效時間時,伺服器就可以認為客戶端已經停止了活動,才會把session刪除以節省儲存空間

很明顯,伺服器的session由伺服器自己維護,客戶端在有效期內都可以記錄,但是不小心清了cookies,就會導致登入失敗,會重新分配新的session和id,那麼老的session會在自己配置的時間內消失

session的生命週期就是:

建立:第一次呼叫getSession()

銷燬:

1、超時,預設30分鐘

2、執行api:session.invalidate()將session物件銷燬、setMaxInactiveInterval(int interval) 設定有效時間,單位秒

3、伺服器非正常關閉

如果正常關閉,session就會被持久化(寫入到檔案中,因為session預設的超時時間為30分鐘,正常關閉後,就會將session持久化,等30分鐘後,就會被刪除)

  • set_expiry(value):設定會話的超時時間
  • 如果沒有指定,則兩個星期後過期
  • 如果value是一個整數,會話將在values秒沒有活動後過期
  • 若果value是一個imedelta物件,會話將在當前時間加上這個指定的日期/時間過期
  • 如果value為0,那麼使用者會話的Cookie將在使用者的瀏覽器關閉時過期
  • 如果value為None,那麼會話永不過期

4.session id的URL重寫

當瀏覽器將cookie禁用,基於cookie的session將不能正常工作,每次使用request.session都將建立一個新的session。達不到session共享資料的目的,但是我們知道原理,只需要將session id 傳遞給伺服器session就可以正常工作的。

以下是JAVA的解決方案

解決:通過URL將session id 傳遞給伺服器:URL重寫

手動方式: url;jsessionid=....

api方式:

encodeURL(java.lang.String url) 進行所有URL重寫

encodeRedirectURL(java.lang.String url) 進行重定向 URL重寫

這兩個用法基本一致,只不過考慮特殊情況,要訪問的連結可能會被Redirect到其他servlet去進行處理,這樣你用上述方法帶來的session的id資訊不能被同時傳送到其他servlet.這時候用encodeRedirectURL()方法就可以了 

如果瀏覽器禁用cooke,api將自動追加session id ,如果沒有禁用,api將不進行任何修改。

注意:如果瀏覽器禁用cookie,web專案的所有url都需進行重寫。否則session將不能正常工作當禁止了cookie時,

 

四、總結

從性質上講,Session即回話,指一種持續性的,雙向的連線。對於web而言,Session指使用者在瀏覽某個網站時,從進入網站到瀏覽器關閉這段時間的會話。所以,Session實際上是一個特定的時間概念。

如果沒有設定Session的生命週期,則SessionID儲存在記憶體中,此時關閉瀏覽器Session自動登出。而我們已經知道,sessionID是通過PHPSESSID這個Cookie儲存在本地的。那麼在瀏覽器不禁用Cookie的前提下,當然可以通過setcookie()或者seession_set_cookie_params()函式設定Session的生存期,Session過期後,PHP會對其進行回收。所以,Session並非都是隨著瀏覽器的關閉而消失的。

當然,如果你的瀏覽器禁用Cookie,那麼所有所有Session的生存週期都是瀏覽器程式,關閉瀏覽器,再次請求頁面又將重新生成Session。不過我們也有其他辦法進行sessionID的傳遞,比如URL傳參,但是這種方式極度危險,強烈不推薦。

例如你開啟一個網站要登入,這個時候就會有session記錄登入之前的資訊,如果登入了就會保持登陸後的資訊,可以理解為打電話,電話打通了,伺服器一個人接了很多電話,對方通過session標識這段對話的對方是誰,如果我結束通話了,下一次打電話的時候自動帶上cookies裡面的session,對方接起電話就知道是誰了,看下我後臺的資料是否失效,沒失效的話繼續剛才的話題聊下去,這就保持了狀態

問題一:什麼是cookie和什麼是session?

cookie是一種在客戶端記錄使用者資訊的技術,因為http協議是無狀態的,為了解決這個問題而產生了cookie。記錄使用者名稱等一些應用

session是一種在服務端記錄使用者資訊的技術,一般session用來在伺服器端共享資料,

session一般情況下依賴於cookies,session建立出來把id通過cookies傳遞,然後session可以存在記憶體中比如redis,亦或者存入mysql,主要看你服務端的配置

問題二:cookie的工作原理?session的工作原理?

cookie工作原理,可以看上面講解cookie的那張圖,cookie是由伺服器端建立傳送回瀏覽器端的,並且每次請求伺服器都會將cookie帶過去,以便伺服器知道該使用者是哪一個。其cookie中是使用鍵值對來儲存資訊的,並且一個cookie只能儲存一個鍵值對。所以在獲取cookie時,是會獲取到所有的cookie,然後從其中遍歷。

session的工作原理就是依靠cookie來做支撐,第一次使用request.session時session被建立,並且會為該session建立一個獨一無二的sessionid存放到cookie中,然後傳送會瀏覽器端,瀏覽器端每次請求時,都會帶著這個sessionid,伺服器就會認識該sessionid,知道了sessionid就找得到哪個session。以此來達到共享資料的目的。 這裡需要注意的是,session不會隨著瀏覽器的關閉而死亡,而是等待超時時間。

問題三:為什麼需要使用cookie和session

可以看看那個會員卡的例子,cookie和session只是為了解決http協議無狀態的這種缺陷,為了記錄使用者資訊,記錄瀏覽器和伺服器之間的狀態和衍生出來的。

問題四:iOS端的cookies如何實現自登陸

  • NSHTTPCookieStorage 這個類就是一個單例,它的主要任務就是管理 Cookies, 增刪改查等各種
  • NSURLRequest NSURLRequest是HTTP請求協議URL資源的訊息物件Request
  • NSHTTPURLResponse

    NSHTTPURLResponse 是HTTP協議請求URL資源的響應訊息物件。這個物件將HTTP協議的序列化了,可以很方便的獲得的狀態碼(statusCode),訊息報頭(allHeaderFields)等資訊

手動管理cookies

  • 從 NSHTTPURLResponse 獲取伺服器發給我們的 Cookie,此種方式獲取的是Headers中的
NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
    NSDictionary *allHeaderFieldsDic = response.allHeaderFields;
    NSString *setCookie = allHeaderFieldsDic[@"Set-Cookie"];
    if (setCookie != nil) {
         NSString *cookie = [[setCookie componentsSeparatedByString:@";"] objectAtIndex:0];
         NSLog(@"cookie : %@", cookie); // 這裡可對cookie進行儲存     }
  • 從 NSHTTPCookieStorage 獲取想要Cookie,此種獲取方式是獲取的cookies中的
//獲取cookie     NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage]cookiesForURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",kBaseURL,[NSString stringWithFormat:@"/index.php?route=mapi/%@",urlstring]]]];
    for (NSHTTPCookie *tempCookie in cookies)
    {
        //列印cookies         NSLog(@"getCookie:%@",tempCookie);
    }
    NSDictionary *Request = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    
    NSUserDefaults *userCookies = [NSUserDefaults standardUserDefaults];
    
    [userCookies setObject:[Request objectForKey:@"Cookie"] forKey:@"cookie"];
    [userCookies synchronize];
  • 清楚cookies
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *_tmpArray = [NSArray arrayWithArray:[cookieStorage cookies]];
    for (id obj in _tmpArray) {
        [cookieStorage deleteCookie:obj];
    }

AFNetworking 3.0管理

  • AFNetworking 3.0 預設是儲存cookies的。
  • 模擬登入,儲存cookie以及設定cookie:
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFHTTPSessionManager *httpManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"hostURL"] sessionConfiguration:sessionConfiguration];
AFHTTPRequestSerializer *requestSerialization = [AFHTTPRequestSerializer serializer];
requestSerialization.timeoutInterval = 15;

// 設定自動管理Cookies requestSerialization.HTTPShouldHandleCookies = YES;

// 如果已有Cookie, 則把你的cookie符上 NSString *cookie = [[NSUserDefaults standardUserDefaults] objectForKey:@"cookie"];
    if (cookie != nil) {
        [requestSerialization setValue:cookie forHTTPHeaderField:@"Cookie"];
    }

// 安全策略 AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;

[httpManager POST:@"logInURL"
       parameters:nil
         progress:NULL
          success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
              if ([responseObject[@"status"] isEqualToString:@"SUCCESS"]) {
                  //獲取 Cookie                   NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
                  NSDictionary *allHeaderFieldsDic = response.allHeaderFields;
                  NSString *setCookie = allHeaderFieldsDic[@"Set-Cookie"];
                  if (setCookie != nil) {
                      NSString *cookie = [[setCookie componentsSeparatedByString:@";"] objectAtIndex:0];
                      // 這裡對cookie進行儲存                       [[NSUserDefaults standardUserDefaults] setObject:cookie forKey:@"cookie"];
                  }
              }else{
                  // 登入失敗               }
          }
          failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
              NSString *errorMessage = error.userInfo[@"NSLocalizedDescription"];
          }];

web就不需要說了,很簡單,都是自帶的東西,只要控制消失方式就好。

問題五:iOS端不用cookies用後臺自定義Token登入

一般情況都可以用Cookies來保證使用者行為和一段時間的登入態。如果不用自帶的,後臺可以自己根據時間戳和其他方式自定義生成token來進行管理,這樣子自定義更強。例如登入的時候一個介面1,成功返回token給我們,我們記錄token到本地,每次請求都帶上,沒有的話就空串

[manager.requestSerializer setValue:[MTFUtils shared].autoToken forHTTPHeaderField:@"Authorization"];

自登陸的時候開一個介面2來校驗token‘是否失效,cookies的話不能很好的控制時間,我們自定義的話可以隨意控制時間,每個介面都可以進行檢測控制,後臺返回固定的錯誤碼來告知客戶端登入失效,重新登入。而且這個模式還能用來保證介面防刷,過多的請求,可能和自登陸沒關係,但是token’的機制,可以讓我們請求一些關鍵的介面時再請求一個獲取token的值,用這個值來隨意控制使用者的請求行為,防止無限刷接

 

問題六:我們一般認為 Cookie 執行在客戶端而 Session 執行在伺服器端,所以當我們關閉瀏覽器(即將客戶端和伺服器端的連結斷開)時,Session 一般就消失了而 Cookie 可以保留。這是真的嗎?

雖然Session的確是執行在伺服器的,但是sessionID卻通過Cookie儲存在客戶端,所以也不盡然。可以自己設定失效是隻存在記憶體中還是本地也儲存

 

問題七:瀏覽器禁止 Cookie,Cookie 就不能用了,但 Session 不會受到影響,這是真的嗎?

禁止了Cookie,頁面的SessionID將無法使用PHPSESSID進行傳遞,大家可以先登陸某一網站,然後刪除瀏覽器資料,會發現重新整理頁面或切換頁面後將丟失登陸狀態,當然我們可以用其他方式替代Cookie進行Session傳值,但是很明顯,Session會受Cookie禁用的影響。

問題八:Session 是否真的比 Cookie 更加安全呢?

存在本地的 Cookie 確實存在一些不安全因素,但是沒人會把安全驗證完全放在前端,而且我們知道一般 Session 是通過 sessionID 和 Cookie 進行繫結的,客戶端的 Cookie 一旦被劫持就相當與 Session 被劫持,伺服器驗證 Cookie 的同時將原封不動地完成對Session的驗證,所以Session比Cookie安全純屬無稽之談。

問題九:我們發現,使用 IE 登陸騰訊網後,在同一臺機子上使用 Firefox 開啟騰訊的頁面,發現已經有了登陸的狀態,那麼是否說明 Cookie 可以在不同瀏覽器之間共享呢?

cookie是由瀏覽器等客戶端完全獨立管理的。因為不同瀏覽器的Cookie管理機制不同,所以cookie不可能在瀏覽器之間共享。對於這個問題,其實是因為我們在安裝騰訊QQ時自動安裝了針對不同瀏覽器的外掛,可以識別已經登陸的QQ號碼而自動登陸。朋友們可以試試把QQ完全解除安裝再從網頁登陸騰訊網,所以這和Cookie共享是完全沒有任何關係的。

問題十:如果把別人的 Cookie 複製到我的電腦上,假設我使用一樣的瀏覽器,那麼我是否可以直接登陸別人的賬號呢?

原則上講是可行的,我們將其稱為 Cookie 劫持,然而我們可以通過在 Cookie 中加入基於IP等特定資訊的引數優化 Cookie 的驗證過程,從而避免這一危險。

 

參考文獻

https://oragekk.me/07-05-2017/iOS%E7%9A%84Cookie%E4%BD%BF%E7%94%A8.html

https://www.cnblogs.com/whgk/p/6422391.html

https://www.jianshu.com/p/bff550b3ead4

https://xujimmy.com/2017/01/11/cookie-session.html

https://blog.csdn.net/hjtl1992/article/details/26006867

GET和POST

GET和POST是HTTP請求的兩種基本方法,要說它們的區別,接觸過WEB開發的人都能說出一二。最直觀的區別就是GET把引數包含在URL中,POST通過request body傳遞引數。

你輕輕鬆鬆的給出了一個“標準答案”:

  • GET在瀏覽器回退時是無害的,而POST會再次提交請求。

  • GET產生的URL地址可以被Bookmark,而POST不可以。

  • GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。

  • GET請求只能進行url編碼,而POST支援多種編碼方式。

  • GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。

  • GET請求在URL中傳送的引數是有長度限制的,而POST麼有。

  • 對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。

  • GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。

  • GET引數通過URL傳遞,POST放在Request body中。

GET和POST是什麼?HTTP協議中的兩種傳送請求的方法。HTTP是什麼?HTTP是基於TCP/IP的關於資料如何在全球資訊網中如何通訊的協議。HTTP的底層是TCP/IP。所以GET和POST的底層也是TCP/IP,也就是說,GET/POST都是TCP連結。GET和POST能做的事情是一樣一樣的。你要給GET加上request body,給POST帶上url引數,技術上是完全行的通的。 

那麼,“標準答案”裡的那些區別是怎麼回事?

在我大全球資訊網世界中,TCP就像汽車,我們用TCP來運輸資料,它很可靠,從來不會發生丟件少件的現象。但是如果路上跑的全是看起來一模一樣的汽車,那這個世界看起來是一團混亂,送急件的汽車可能被前面滿載貨物的汽車攔堵在路上,整個交通系統一定會癱瘓。為了避免這種情況發生,交通規則HTTP誕生了。HTTP給汽車運輸設定了好幾個服務類別,有GET, POST, PUT, DELETE等等,HTTP規定,當執行GET請求的時候,要給汽車貼上GET的標籤(置method為GET),而且要求把傳送的資料放在車頂上(url中)以方便記錄。如果是POST請求,就要在車上貼上POST的標籤,並把貨物放在車廂裡。當然,你也可以在GET的時候往車廂內偷偷藏點貨物,但是這是很不光彩;也可以在POST的時候在車頂上也放一些資料,讓人覺得傻乎乎的。HTTP只是個行為準則,而TCP才是GET和POST怎麼實現的基本。

但是,我們只看到HTTP對GET和POST引數的傳送渠道(url還是requrest body)提出了要求。“標準答案”裡關於引數大小的限制又是從哪來的呢?

在我大全球資訊網世界中,還有另一個重要的角色:運輸公司。不同的瀏覽器(發起http請求)和伺服器(接受http請求)就是不同的運輸公司。 雖然理論上,你可以在車頂上無限的堆貨物(url中無限加引數)。但是運輸公司可不傻,裝貨和卸貨也是有很大成本的,他們會限制單次運輸量來控制風險,資料量太大對瀏覽器和伺服器都是很大負擔。業界不成文的規定是,(大多數)瀏覽器通常都會限制url長度在2K個位元組,而(大多數)伺服器最多處理64K大小的url。超過的部分,恕不處理。如果你用GET服務,在request body偷偷藏了資料,不同伺服器的處理方式也是不同的,有些伺服器會幫你卸貨,讀出資料,有些伺服器直接忽略,所以,雖然GET可以帶request body,也不能保證一定能被接收到哦。

好了,現在你知道,GET和POST本質上就是TCP連結,並無差別。但是由於HTTP的規定和瀏覽器/伺服器的限制,導致他們在應用過程中體現出一些不同

GET和POST還有一個重大區別,簡單的說:

GET產生一個TCP資料包;POST產生兩個TCP資料包。

長的說:

對於GET方式的請求,瀏覽器會把http header和data一併傳送出去,伺服器響應200(返回資料);而對於POST,瀏覽器先傳送header,伺服器響應100 continue,瀏覽器再傳送data,伺服器響應200 ok(返回資料)。

也就是說,GET只需要汽車跑一趟就把貨送到了,而POST得跑兩趟,第一趟,先去和伺服器打個招呼“嗨,我等下要送一批貨來,你們開啟門迎接我”,然後再回頭把貨送過去。

因為POST需要兩步,時間上消耗的要多一點,看起來GET比POST更有效。因此Yahoo團隊有推薦用GET替換POST來優化網站效能。但這是一個坑!跳入需謹慎。為什麼?

1. GET與POST都有自己的語義,不能隨便混用。

2. 據研究,在網路環境好的情況下,發一次包的時間和發兩次包的時間差別基本可以無視。而在網路環境差的情況下,兩次包的TCP在驗證資料包完整性上,有非常大的優點。

3. 並不是所有瀏覽器都會在POST中傳送兩次包,Firefox就只傳送一次。

 

 

 

 

 

 

 

 

相關文章