1、引言

隨著瓜子二手車相關業務的發展,公司有多個業務線都接入了IM系統,IM系統中的Socket長連接的安全問題變得越來越重要。本次分享正是基於此次解決Socket長連接身份安全認證的實踐總結而來,方案可能並不完美,但願能起到拋磚引玉的作用,希望能給您的IM系統開發帶來啟發。

學習交流:

- 即時通訊/推送技術開發交流4群:101279154[推薦]

- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》

(本文同步發佈於:52im.net/thread-2106-1-

2、原作者

封宇:瓜子二手車技術專家,中國計算機學會專業會員。主要負責瓜子即時消息解決方案及相關係統研發工作。曾供職於58同城、華北計算技術研究所,參與到家消息系統、58爬蟲系統以及多個國家級軍工科研項目的架構及研發工作。

封宇同時還分享了其它IM方面的技術實踐和總結,您可能也會感興趣:

《從零開始搭建瓜子二手車IM系統(PPT) [附件下載]》

《一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)》《一個低成本確保IM消息時序的方法探討》《移動端IM中大規模群消息的推送如何保證效率、實時性?》

3、系列文章

本文是IM通訊安全知識系列文章中的第7篇,總目錄如下:

《即時通訊安全篇(一):正確地理解和使用Android端加密演算法》《即時通訊安全篇(二):探討組合加密演算法在IM中的應用》

《即時通訊安全篇(三):常用加解密演算法與通訊安全講解》

《即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險》《即時通訊安全篇(五):對稱加密技術在Android上的應用實踐》《即時通訊安全篇(六):非對稱加密技術的原理與應用實踐》《即時通訊安全篇(七):用JWT技術解決IM系統Socket長連接的身份認證痛點》(本文)

4、我們面臨的技術痛點

針對我們IM系統中的Socket長連接的身份認證安全問題,瓜子有統一登錄認證系統SSO(即單點登陸系統,原理詳見《IM開發基礎知識補課(一):正確理解前置HTTP SSO單點登陸介面的原理》)。

我們的IM長連接通道也利用這個系統做安全認證,結構如下圖:

如上圖所示,整個認證步驟如下:

1)用戶登錄App,App從業務後台拿到單點登陸系統SSO頒發的token;

2)當App需要使用IM功能時,將token傳給IM客服端SDK;

3)客服端SDK跟IM Server建立長連接的時候用token進行認證;

4)IM Server請求SSO單點登陸系統,確認token合法性。

* 補充:如您對SSO單點登陸系統的了解知之甚少,請務必先閱讀《IM開發基礎知識補課(一):正確理解前置HTTP SSO單點登陸介面的原理》。

咋一看,這個過程沒有什麼問題,但是IM(尤其是移動端IM)業務的特殊性,這個流程結構並不好。

為什麼說上面的流程結構對於移動端的IM來說並不好呢?原因如下:

1)網路不穩定:手機(移動端)的網路很不穩定,進出地鐵可能斷網,挪動位置也可能換基站;

2)長連接頻繁建立和釋放:正因為1)中的原因,在一個聊天會話過程中,會經常重新建立長連接,從而導致上圖裡的第3步會被頻繁執行,進而第4步也會頻繁執行;

3)系統壓力會增大:鑒於2)中的表現,將大大增加了SSO單點登陸系統的壓力(因為IM實例需要頻繁的調用SSO系統,從而完全客戶端長連接的身份合法性檢查);

4)用戶體驗也不好:長連接建立過程中,因SSO單點登陸系統並不屬於IM服務端實例範圍之內,IM服務端實例與SSO系統的通信等,帶來的額外通信鏈路延遲對於用戶的體驗也是一種傷害(而且SSO系統也可能短暫開小差)。

如果不通過上圖中的第4步就能完成IM長連接的身份合法性驗證,那這個痛點會得到極大緩解。於是,我們便想到了JWT技術。

* 題外話:如果您對移動端弱網路的物理特性還不了解,那麼下面的文章有助於您建立起這方面的認知:

《現代移動端網路短連接的優化手段總結:請求速度、弱網適應、安全保障》

《移動端IM開發者必讀(一):通俗易懂,理解移動網路的「弱」和「慢」》

《移動端IM開發者必讀(二):史上最全移動弱網路優化方法總結》

5、完全搞懂什麼是JWT技術

5.1 基礎知識

JSON Web Token(簡稱JWT),是一個開放安全的行業標準(詳見RFC7519),可以用於多個系統之間傳遞安全可靠的信息(也包括本文中將要用到的傳遞身份認證信息的場景)。

一個完整的JWT的token字元串是什麼樣子的結構?

▲ JWT說到底也是一個token字元串,它由三部分組成:頭部、載荷與簽名

正如上圖中所示,一個JWT的token字元串組成如下:

1)紅色的為Header:指定token類型與簽名類型;

2)紫色的為載荷(playload):存儲用戶id等關鍵信息;

3)藍色的為簽名:保證整個信息的完整性、可靠性(這個簽名字元串,相當於是一段被加密了的密文文本,安全性就是由它來決定的)。

5.2解密JWT的頭部(Header)

JWT的頭部用於描述關於該JWT的最基本的信息,例如其類型以及簽名所用的演算法等。

這可以被表示成一個JSON對象:

{

"typ": "JWT","alg": "HS256"}

▲ 在這個頭信息里,標明了這是一個JWT字元串,並且所用的簽名演算法是HS256演算法

對它進行Base64編碼,之後的字元串就成了JWT的Header(頭部),也就是你在5.1節中看到的紅色部分:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

(你可以自已試著進行Base64的加密和解決,比如用這個在線工具:tool.oschina.net/encryp

5.3 解密JWT的載荷(playload)

在載荷(playload)中可以定義以下屬性:

1)iss: 該JWT的簽發者;

2)sub: 該JWT所面向的用戶;

3)aud: 接收該JWT的一方;

4)exp(expires): 什麼時候過期,這裡是一個Unix時間戳;

5)iat(issued at): 在什麼時候簽發的。

上面的信息也可以用一個JSON對象來描述,將上面的JSON對象進行base64編碼,可以得到下面的字元串。

這個字元串我們將它稱作JWT的Payload(載荷),以下字串樣例就是你在5.1節中看到的紫色部分:

eyJpc3MiOiIyOWZmMDE5OGJlOGM0YzNlYTZlZTA4YjE1MGRhNTU0NC1XRUIiLCJleHAiOjE1MjI0OTE5MTV9

(你可以自已試著進行Base64的加密和解決,比如用這個在線工具:tool.oschina.net/encryp

5.4 解決JWT的簽名(Signature)

JWT的簽名部分,在官方文檔中是如下描述的:

HMACSHA256(

base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

上述偽碼的意義,即如下操作:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIyOWZmMDE5OGJlOGM0YzNlYTZlZTA4YjE1MGRhNTU0NC1XRUIiLCJleHAiOjE1MjI0OTE5MTV9

▲ 將上面的兩個base64編碼後的字元串都用句號『.』連接在一起(頭部在前),就形成了如下字元串

最後,我們將上面拼接完的字元串用HS256演算法進行加密。在加密的時候,我們還需要提供一個密鑰(secret)。

那麼,按照RFC7519上描述的方法,就可以得到我們加密後的內容:

P-k-vIzxElzyzFbzR4tUxAAET8xT9EP49b7hpcPazd0

▲ 這個就是我們需要的JWT的簽名部分了

5.5 簽名的目的

生成JWT的token字元串的最後一步簽名過程,實際上是對頭部以及載荷內容進行加密。

一般而言:加密演算法對於不同的輸入產生的輸出總是不一樣的。所以,如果有人對頭部以及載荷的內容解碼之後進行修改,再進行編碼的話,那麼新的頭部和載荷的簽名和之前的簽名就將是不一樣的。而且,如果不知道伺服器加密的時候用的密鑰的話,得出來的簽名也一定會是不一樣的。

換句話說:你的JWT字元串的安全強度,基本上就是由這個簽名部分來決定的。

使用時:伺服器端在接受到JWT的token字元串後,會首先用開發者指明的secret(可以理解為密碼)對頭部和載荷的內容用同一演算法再次簽名。那麼伺服器應用是怎麼知道我們用的是哪一種演算法呢?別忘了,我們在JWT的頭部中已經用alg欄位指明了我們的加密演算法了。

如果伺服器端對頭部和載荷再次以同樣方法簽名之後發現,自己計算出來的簽名和接受到的簽名不一樣,那麼就說明這個Token的內容被別人動過的,我們應該拒絕這個JWT Token,返回一個HTTP 401 Unauthorized響應。

5.6 一個典型的JWT應用流程

JWT是一個怎樣的流程? 先上個官方文檔的圖:

如上圖所示,整個應用流程描述如下:

1)客戶端使用賬戶密碼請求登錄介面;

2)登錄成功後伺服器使用簽名密鑰生成JWT ,然後返回JWT給客戶端;

3)客戶端再次向服務端請求其他介面時帶上JWT;

4)服務端接收到JWT後驗證簽名的有效性.對客戶端做出相應的響應。

5.7 總而言之

JWT的整個技術原理,就是一個很典型的對稱加密應用過程,通俗的說也就是用開發者在服務端保存的密碼,對用戶的id等信息進行加密並按照JWT的規則(見5.1節)組成字元串返回給用戶。用戶在使用時將這個字元串提交給對應的服務端,服務端取出JWT字串的頭信息、載荷,用開發者指明的密碼試著進行加密並得到一個字元串(即合法的JWT token),兩相比較,相同則認為用戶提交上來的JWT合法,否則不合法。這就是JWT的全部原理,相當簡單易懂。

JWT技術的價值不在於具體的技術實現,而在於它的思想本身,尤其在異構系統、分散式系統方面,可以極大的簡化安全認證的成本,包括簡化架構複雜性、降低使用門檻等,因為JWT的技術原理決定了認證的過程不需要其它系統的參與,由當前實例自已就可以完成,而成認證代碼極小(就是一個加密字元串的比較而已)。

它的技術思路在當前的各種開發系統中應用廣泛,比如下圖中微信公眾號的服務介面配置里,也用到了類似的思想:

另外,蘋果著名的APNs推送服務,也支持JWT技術,詳見《基於APNs最新HTTP/2介面實現iOS的高性能消息推送(服務端篇)》第6.2節:

▲ 上述截圖內容摘錄自蘋果官方開發者文檔

6、我們是怎樣使用JWT技術的?

上一章節,我們詳細理解了JWT技術的原理,那麼回到本文的初衷:我們該如何使用JWT技術來解決上面所提到的通點呢?

我們採用JWT驗證IM的Socket長連接流程如下:

如上圖所示,整個驗證過程描述如下:

1)用戶登錄App(使用IM客服端SDK),App從業務後台拿到SSO單點登陸系統頒發的token(注意:此token還不是JWT的token,它將在第3)步中被使用並生成真正的JWT token);

2)當App需要使用IM功能時,將token傳給IM客服端SDK(這是在客戶端完成的,即當App的功能調用IM客服端SDK時傳入);

3)IM客服端SDK將用戶名及第2步中得到的token發給後台的JWT Server(簽發JWT token的模塊),請求JWT token;

4)收到第3)步中提交過來的token後,JWT Server會通過RPC等技術向SSO系統提交驗證此token的合法性,如果合法,將用跟IM Server約定的Secret(你可以理解為這就是一個固定的密碼而已),根據業務需要簽發JWT token,並最終返回給IM客服端SDK(即完成第3步中的請求)。

5)後緒,IM客服端SDK將使用得到的JWT token請求IM Server驗證長連接,IM Server根據約定的演算法(不依賴其他系統直接用JWT的規則,加上第4)步中與JWT Server 約定的Secret)即可完成jwttoken合法性驗證。

通過上述努力,移動端在弱網情況下的頻繁建立長連接的身份驗證痛點得到了解決。

7、JWT技術的缺點

當然,我們之所以選擇JWT技術,主要看重的還是它簡單易用,但或許正因為如此,某種程度上來說這也恰是居致它的缺點的原因所在。

JWT技術的缺點及建議的解決方法主要有:

1)JWT的最大缺點是伺服器不保存會話狀態,所以在使用期間不可能取消token或更改token的許可權。也就是說,一旦JWT簽發,在有效期內將會一直有效;

2)JWT本身包含認證信息(即你在第5.1節中看到的頭信息、負載信息),因此一旦信息泄露,任何人都可以獲得token的所有許可權。為了減少盜用,JWT的有效期不宜設置太長。對於某些重要操作,用戶在使用時應該每次都進行進行身份驗證;

3)為了減少盜用和竊取,JWT不建議使用HTTP協議來傳輸代碼,而是使用加密的HTTPS(SSL)協議進行傳輸。

以下這篇文章列了一些適用JWT的應用場景,僅供參考:

jianshu.com/p/af8360b83

8、點評

JWT其實是一項比較有爭議的技術,誇它的人會說它簡單易用、成本低,極度貶低它的人會說它的安全性就像一層窗戶紙——捅一下就破了。

不可否認,跟當前流行的非對稱加密技術(大家最熟悉的HTTPS協議就是一個典型的非對稱加密應用場景)相比,JWT技術的安全係數確實相對要低一些,因為JWT技術的本質就是對稱加密技術的應用,而非對稱加密技術出現的原因也就是為了提升對稱加密技術所不具有的一些安全性。

但非對稱加密技術這麼好,也並不意味著對稱加密技術就一無是處,因為並不是所有場景都需要用性能、架構的複雜性、運維成本來換取高安全性,還是那句話:「安全這東西,夠用就行」,而這也正是JWT這種技術仍然有其價值的原因所在。

非對稱加密技術雖然安全,但也並非理論上的無懈可擊,這世上還沒有絕對安全的演算法,總之,不苛責級極致安全的情況下,夠用便好,你說呢?

如果您對對稱加密和非對稱加密技術的還不是太了解,可以閱讀以下文章:

《即時通訊安全篇(三):常用加解密演算法與通訊安全講解》

《即時通訊安全篇(六):非對稱加密技術的原理與應用實踐》

附錄:更多即時通訊方面的文章

如果您是IM開發初學者,強烈建議首先閱讀:

《新手入門一篇就夠:從零開發移動端IM》即時通訊安全方面的文章匯總如下:《即時通訊安全篇(一):正確地理解和使用Android端加密演算法》《即時通訊安全篇(二):探討組合加密演算法在IM中的應用》《即時通訊安全篇(三):常用加解密演算法與通訊安全講解》《即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險》《即時通訊安全篇(五):對稱加密技術在Android平台上的應用實踐》《即時通訊安全篇(六):非對稱加密技術的原理與應用實踐》《即時通訊安全篇(七):用JWT技術解決IM系統Socket長連接的身份認證痛點》《傳輸層安全協議SSL/TLS的Java平台實現簡介和Demo演示》《理論聯繫實際:一套典型的IM通信協議設計詳解(含安全層設計)》《微信新一代通信安全解決方案:基於TLS1.3的MMTLS詳解》《來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享》《簡述實時音視頻聊天中端到端加密(E2EE)的工作原理》《移動端安全通信的利器——端到端加密(E2EE)技術詳解》《Web端即時通訊安全:跨站點WebSocket劫持漏洞詳解(含示例代碼)》《通俗易懂:一篇掌握即時通訊的消息傳輸安全原理》《IM開發基礎知識補課(四):正確理解HTTP短連接中的Cookie、Session和Token》《快速讀懂量子通信、量子加密技術》《即時通訊安全篇(七):如果這樣來理解HTTPS原理,一篇就夠了》《一分鐘理解 HTTPS 到底解決了什麼問題》>> 更多同類文章 ……

(本文同步發佈於:52im.net/thread-2106-1-


推薦閱讀:
相关文章