本文引用了簡書做者「騎小豬看流星」技術文章「Cookie、Session、Token那點事兒」的部份內容,感謝原做者。php
衆所周之,IM是個典型的快速數據流交換系統,當今主流IM系統(尤爲移動端IM)的數據流交換方式都是Http短鏈接+TCP或UDP長鏈接來實現。Http短鏈接主要用於從服務器讀取各類持久化信息:好比用戶信息、聊天曆史記錄、好友列表等等,長鏈接則是用於實時的聊天消息或指令的接收和發送。html
做爲IM系統中不可或缺的技術,Http短連的重要性無可替代,但Http做爲傳統互聯網信息交換技術,一些典型的概念好比:Cookie、Session、Token,對於IM新手程序員來講並不容易理解。鑑於Http短鏈接在IM系統中的重要性,如何正確地理解Cookie、Session、Token這樣的東西,決定了您的技術方案可否找到最佳實踐。本文將從基礎上講解這3者的原理、用途以及正確地應用場景。前端
題外話:本文討論的使用Http短鏈接的話題可能並不適用於微信這樣的IM,由於微信的短鏈接並不是使用Http標準協議實現,而是基於自研的Mars網絡層框架再造了一套短鏈接機制,從而更適用於IM這種場景(更低延遲、更省流量、更好的弱網適應算法等),詳情請見《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》。固然,Mars雖好,但不必定適合您的團隊,由於定製的方案相較於標準通用方案來講,沒有強大的技術實力,仍是不太容易掌控的了的。程序員
一篇文章:《現代移動端網絡短鏈接的優化手段總結:請求速度、弱網適應、安全保障》這篇文章詳述了現今移動網絡下http短鏈接的網絡層技術問題,有助於更好地理解本文,有興趣的話也推薦讀一讀。web
學習交流:redis
- 即時通信開發交流羣:320837163[推薦]算法
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》數據庫
(本文同步發佈於:http://www.52im.net/thread-1525-1-1.html)express
▼ IM開發乾貨系列文章(本文是其第13篇):編程
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《一種Android端IM智能心跳算法的設計與實現探討(含樣例代碼)》
《IM開發基礎知識補課(一):正確理解前置HTTP SSO單點登錄接口的原理》
《IM開發基礎知識補課(二):如何設計大量圖片文件的服務端存儲架構?》
若是您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。
Cookie 技術產生源於 HTTP 協議在互聯網上的急速發展。隨着互聯網時代的策馬奔騰,帶寬等限制不存在了,人們須要更復雜的互聯網交互活動,就必須同服務器保持活動狀態(簡稱:保活)。因而,在瀏覽器發展初期,爲了適應用戶的需求技術上推出了各類保持 Web 瀏覽狀態的手段,其中就包括了 Cookie 技術。Cookie 在計算機中是個存儲在瀏覽器目錄中的文本文件,當瀏覽器運行時,存儲在 RAM 中發揮做用 (此種 Cookies 稱做 Session Cookies),一旦用戶從該網站或服務器退出,Cookie 可存儲在用戶本地的硬盤上 (此種 Cookies 稱做 Persistent Cookies)。
Cookie 起源:1993 年,網景公司僱員 Lou Montulli 爲了讓用戶在訪問某網站時,進一步提升訪問速度,同時也爲了進一步實現我的化網絡,發明了今天普遍使用的 Cookie。(因此,適當的偷懶也會促進人類計算機發展史的一小步~)
Cookie時效性:目前有些 Cookie 是臨時的,有些則是持續的。臨時的 Cookie 只在瀏覽器上保存一段規定的時間,一旦超過規定的時間,該 Cookie 就會被系統清除。
Cookie使用限制:Cookie 必須在 HTML 文件的內容輸出以前設置;不一樣的瀏覽器 (Netscape Navigator、Internet Explorer) 對 Cookie 的處理不一致,使用時必定要考慮;客戶端用戶若是設置禁止 Cookie,則 Cookie 不能創建。 而且在客戶端,一個瀏覽器能建立的 Cookie 數量最多爲 300 個,而且每一個不能超過 4KB,每一個 Web 站點能設置的 Cookie 總數不能超過 20 個。
執行流程:
A:首先,客戶端會發送一個http請求到服務器端;
B: 服務器端接受客戶端請求後,發送一個http響應到客戶端,這個響應頭,其中就包含Set-Cookie頭部;
C:在客戶端發起的第二次請求(注意:若是服務器須要咱們帶上Cookie,咱們就須要在B步驟上面拿到這個Cookie而後做爲請求頭一塊兒發起第二次請求),提供給了服務器端能夠用來惟一標識客戶端身份的信息。這時,服務器端也就能夠判斷客戶端是否啓用了cookies。儘管,用戶可能在和應用程序交互的過程當中忽然禁用cookies的使用,可是,這個狀況基本是不太可能發生的,因此能夠不加以考慮,這在實踐中也被證實是對的。
爲了方便理解,能夠先看下這張流程執行圖加深概念:
那麼,在瀏覽器上面的請求頭和Cookie在那?下圖給你們截取了其中一種:
衆所周知,HTTP 是一個無狀態協議,因此客戶端每次發出請求時,下一次請求沒法得知上一次請求所包含的狀態數據,如何能把一個用戶的狀態數據關聯起來呢?
好比在淘寶的某個頁面中,你進行了登錄操做。當你跳轉到商品頁時,服務端如何知道你是已經登錄的狀態?
Cookie 雖然很方便,可是使用 Cookie 有一個很大的弊端,Cookie 中的全部數據在客戶端就能夠被修改,數據很是容易被僞造,那麼一些重要的數據就不能存放在 Cookie 中了,並且若是 Cookie 中數據字段太多會影響傳輸效率。爲了解決這些問題,就產生了 Session,Session 中的數據是保留在服務器端的。
總之:Session是對於服務端來講的,客戶端是沒有Session一說的。Session是服務器在和客戶端創建鏈接時添加客戶端鏈接標誌,最終會在服務器軟件(Apache、Tomcat、JBoss)轉化爲一個臨時Cookie發送給給客戶端,當客戶端第一請求時服務器會檢查是否攜帶了這個Session(臨時Cookie),若是沒有則會添加Session,若是有就拿出這個Session來作相關操做。
Session 的運做經過一個session_id來進行。session_id一般是存放在客戶端的 Cookie 中,好比在 express 中(說的是Nodejs),默認是connect.sid這個字段,當請求到來時,服務端檢查 Cookie 中保存的 session_id 並經過這個 session_id 與服務器端的 Session data 關聯起來,進行數據的保存和修改。
這意思就是說,當你瀏覽一個網頁時,服務端隨機產生一個 1024 比特長的字符串,而後存在你 Cookie 中的connect.sid字段中。當你下次訪問時,Cookie 會帶有這個字符串,而後瀏覽器就知道你是上次訪問過的某某某,而後從服務器的存儲中取出上次記錄在你身上的數據。因爲字符串是隨機產生的,並且位數足夠多,因此也不擔憂有人可以僞造。僞形成功的機率比坐在家裏編程時被鄰居家的狗忽然闖入並咬死的概率還低。
一個完整的Cookie+Session應用過程以下圖所示:
Session 能夠存放在:
1)內存;
2)Cookie自己;
3)redis 或 memcached 等緩存中;
4)數據庫中。
線上來講,緩存的方案比較常見,存數據庫的話,查詢效率相比前三者都過低,不推薦;Cookie Session 有安全性問題,下面會提到。
傳統的身份驗證方法從最先的Cookie到Session以及給Session Cookie作個加密,接下來咱們來看看Token認證。
諸如Ember,Angular,Backbone之類的Web前端框架類庫正隨着更加精細的Web應用而日益壯大。正因如此,服務器端的組建也正正在從傳統的任務中解脫,轉而變的更像API。API使得傳統的前端和後端的概念解耦。開發者能夠脫離前端,獨立的開發後端,在測試上得到更大的便利。這種途徑也使得一個移動應用和網頁應用可使用相同的後端。
當使用一個API時,其中一個挑戰就是認證(authentication)。在傳統的web應用中,服務端成功的返回一個響應(response)依賴於兩件事。一是,他經過一種存儲機制保存了會話信息(Session)。每個會話都有它獨特的信息(id),經常是一個長的,隨機化的字符串,它被用來讓將來的請求(Request)檢索信息。其次,包含在響應頭(Header)裏面的信息使客戶端保存了一個Cookie。服務器自動的在每一個子請求裏面加上了會話ID,這使得服務器能夠經過檢索Session中的信息來辨別用戶。這就是傳統的web應用逃避HTTP面向無鏈接的方法(This is how traditional web applications get around the fact that HTTP is stateless)。
API應該被設計成無狀態的(Stateless)。這意味着沒有登錄,註銷的方法,也沒有sessions,API的設計者一樣也不能依賴Cookie,由於不能保證這些request是由瀏覽器所發出的。天然,咱們須要一個新的機制。Token這種東西就應運而生了。
token是用戶身份的驗證方式,咱們一般叫它:令牌。最簡單的token組成:uid(用戶惟一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽以哈希算法壓縮成必定長的十六進制字符串,能夠防止惡意第三方拼接token請求服務器)。還能夠把不變的參數也放進token,避免屢次查庫。
咱們能夠把Token想象成一個安全的護照。你在一個安全的前臺驗證你的身份(經過你的用戶名和密碼),若是你成功驗證了本身,你就能夠取得這個。當你走進大樓的時候(試圖從調用API獲取資源),你會被要求驗證你的護照,而不是在前臺從新驗證。
簡單來講,就像下圖這樣:
Token的使用流程:
A:當用戶首次登陸成功(註冊也是一種能夠適用的場景)以後, 服務器端就會生成一個 token 值,這個值,會在服務器保存token值(保存在數據庫中),再將這個token值返回給客戶端;
B:客戶端拿到 token 值以後,進行本地保存。(SP存儲是你們可以比較支持和易於理解操做的存儲);
C:當客戶端再次發送網絡請求(通常不是登陸請求)的時候,就會將這個 token 值附帶到參數中發送給服務器;
D:服務器接收到客戶端的請求以後,會取出token值與保存在本地(數據庫)中的token值作對比。
Token的身份認證邏輯:
對比一:若是兩個 token 值相同, 說明用戶登陸成功過!當前用戶處於登陸狀態!
對比二:若是沒有這個 token 值, 則說明沒有登陸成功;
對比三:若是 token 值不一樣: 說明原來的登陸信息已經失效,讓用戶從新登陸。
咱們能夠保存認證過的Token記錄在服務器上,來添加一個附加的安全層,而後在每一步驗證Token的時候驗證這個記錄(好比每次客戶端請求API時檢查這個Token的合法性)。這將會阻止第三方假裝一個Token,也將會使得服務器能夠失效一個Token。
1)cookie數據存放在客戶的瀏覽器上,session數據放在服務器上;
2)cookie不是很安全,別人能夠分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session;
3)session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能,考慮到減輕服務器性能方面,應當使用cookie;
4)單個cookie保存的數據不能超過4K,不少瀏覽器都限制一個站點最多保存20個cookie。
因此我的建議:
將登錄信息等重要信息存放爲session;
其餘信息若是須要保留,能夠放在cookie中。
Session和 token並不矛盾,做爲身份認證token安全性比Session好,由於每一個請求都有簽名還能防止監聽以及重放攻擊,而Session就必須靠鏈路層來保障通信安全了。如上所說,若是你須要實現有狀態的會話,仍然能夠增長session來在服務器端保存一些狀態
App一般用restful api跟server打交道。Rest是stateless的,也就是app不須要像browser那樣用cookie來保存Session,所以用Session token來標示本身就夠了,session/state由api server的邏輯處理。若是你的後端不是stateless的rest api,那麼你可能須要在app裏保存Session.能夠在app裏嵌入webkit,用一個隱藏的browser來管理cookie Session.
Session是一種HTTP存儲機制,目的是爲無狀態的HTTP提供的持久機制。所謂Session認證只是簡單的把User信息存儲到Session裏,由於SID的不可預測性,暫且認爲是安全的。這是一種認證手段。而Token,若是指的是OAuth Token或相似的機制的話,提供的是 認證 和 受權 ,認證是針對用戶,受權是針對App。其目的是讓 某App有權利訪問 某用戶 的信息。這裏的Token是惟一的。不能夠轉移到其它App上,也不能夠轉到其它 用戶 上。轉過來講Session。Session只提供一種簡單的認證,即有此SID,即認爲有此User的所有權利。是須要嚴格保密的,這個數據應該只保存在站方,不該該共享給其它網站或者第三方App。因此簡單來講,若是你的用戶數據可能須要和第三方共享,或者容許第三方調用API接口,用Token。若是永遠只是本身的網站,本身的App,用什麼就無所謂了。
Token就是令牌,好比你受權(登陸)一個程序時,他就是個依據,判斷你是否已經受權該軟件;cookie就是寫在客戶端的一個txt文件,裏面包括你登陸信息之類的,這樣你下次在登陸某個網站,就會自動調用cookie自動登陸用戶名;session和cookie差很少,只是Session是寫在服務器端的文件,也須要在客戶端寫入cookie文件,可是文件裏是你的瀏覽器編號。Session的狀態是存儲在服務器端,客戶端只有Session id;而Token的狀態是存儲在客戶端。
[1] 有關IM安全的文章:
《即時通信安全篇(一):正確地理解和使用Android端加密算法》
《即時通信安全篇(四):實例分析Android中密鑰硬編碼的風險》
《即時通信安全篇(五):對稱加密技術在Android平臺上的應用實踐》
《傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示》
《理論聯繫實際:一套典型的IM通訊協議設計詳解(含安全層設計)》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《來自阿里OpenIM:打造安全可靠即時通信服務的技術實踐分享》
《Web端即時通信安全:跨站點WebSocket劫持漏洞詳解(含示例代碼)》
>> 更多同類文章 ……
[2] 有關IM架構設計的文章:
《一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)》
《IM開發基礎知識補課(二):如何設計大量圖片文件的服務端存儲架構?》
《IM開發基礎知識補課(三):快速理解服務端數據庫讀寫分離原理及實踐建議》
《IM開發基礎知識補課(四):正確理解HTTP短鏈接中的Cookie、Session和Token》
>> 更多同類文章 ……
[3] IM開發綜合文章:
《現代移動端網絡短鏈接的優化手段總結:請求速度、弱網適應、安全保障》
《IM開發基礎知識補課:正確理解前置HTTP SSO單點登錄接口的原理》
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊原創分享(一):如何大幅提高移動網絡下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮移動網絡下APP的流量消耗(上篇)》
《騰訊原創分享(二):如何大幅壓縮移動網絡下APP的流量消耗(下篇)》
《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》
《基於社交網絡的Yelp是如何實現海量用戶圖片的無損壓縮的?》
>> 更多同類文章 ……
(本文同步發佈於:http://www.52im.net/thread-1525-1-1.html)