在做介面測試時,經常會碰到請求參數為token的類型,但是可能大部分測試人員對token,cookie,session的區別還是一知半解。為此我查閱大量的資料做瞭如下總結。 此篇文章也許是最全最通俗的關於Token ,Cookie和Session的區別的文章,好好揣摩文章的每一個字,也許你會有更深的 ...
在做介面測試時,經常會碰到請求參數為token的類型,但是可能大部分測試人員對token,cookie,session的區別還是一知半解。為此我查閱大量的資料做瞭如下總結。
此篇文章也許是最全最通俗的關於Token ,Cookie和Session的區別的文章,好好揣摩文章的每一個字,也許你會有更深的理解!
Cookie
cookie 是一個非常具體的東西,指的就是瀏覽器裡面能永久存儲的一種數據,僅僅是瀏覽器實現的一種數據存儲功能。
cookie由伺服器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給伺服器。由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁碟空間,所以每個域的cookie數量是有限的。
Session
session 從字面上講,就是會話。這個就類似於你和一個人交談,你怎麼知道當前和你交談的是張三而不是李四呢?對方肯定有某種特征(長相等)表明他就是張三。
session 也是類似的道理,伺服器要知道當前發請求給自己的是誰。為了做這種區分,伺服器就要給每個客戶端分配不同的“身份標識”,然後客戶端每次向伺服器發請求的時候,都帶上這個“身份標識”,伺服器就知道這個請求來自於誰了。至於客戶端怎麼保存這個“身份標識”,可以有很多種方式,對於瀏覽器客戶端,大家都預設採用 cookie 的方式。
伺服器使用session把用戶的信息臨時保存在了伺服器上,用戶離開網站後session會被銷毀。這種用戶信息存儲方式相對cookie來說更安全,可是session有一個缺陷:如果web伺服器做了負載均衡,那麼下一個操作請求到了另一臺伺服器的時候session會丟失。
Token
token的意思是“令牌”,是用戶身份的驗證方式,最簡單的token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽以哈希演算法壓縮成一定長的十六進位字元串,可以防止惡意第三方拼接token請求伺服器)。還可以把不變的參數也放進token,避免多次查庫
傳統身份驗證
HTTP 是一種沒有狀態的協議,也就是它並不知道是誰是訪問應用。這裡我們把用戶看成是客戶端,客戶端使用用戶名還有密碼通過了身份驗證,不過下回這個客戶端再發送請求時候,還得再驗證一下。
解決的方法就是,當用戶請求登錄的時候,如果沒有問題,我們在服務端生成一條記錄,這個記錄里可以說明一下登錄的用戶是誰,然後把這條記錄的 ID 號發送給客戶端,客戶端收到以後把這個 ID 號存儲在 Cookie 里,下次這個用戶再向服務端發送請求的時候,可以帶著這個 Cookie ,這樣服務端會驗證一個這個 Cookie 里的信息,看看能不能在服務端這裡找到對應的記錄,如果可以,說明用戶已經通過了身份驗證,就把用戶請求的數據返回給客戶端。
上面說的就是 Session,我們需要在服務端存儲為登錄的用戶生成的 Session ,這些 Session 可能會存儲在記憶體,磁碟,或者資料庫里。我們可能需要在服務端定期的去清理過期的 Session 。
基於 Token 的身份驗證
使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:
- 客戶端使用用戶名跟密碼請求登錄
- 服務端收到請求,去驗證用戶名與密碼
- 驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
- 客戶端收到 Token 以後可以把它存儲起來,比如放在 Cookie 里或者 Local Storage 里
- 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 Token
- 服務端收到請求,然後去驗證客戶端請求裡面帶著的 Token,如果驗證成功,就向客戶端返回請求的數據
APP登錄的時候發送加密的用戶名和密碼到伺服器,伺服器驗證用戶名和密碼,如果成功,以某種方式比如隨機生成32位的字元串作為token,存儲到伺服器中,並返回token到APP,以後APP請求時,凡是需要驗證的地方都要帶上該token,然後伺服器端驗證token,成功返回所需要的結果,失敗返回錯誤信息,讓他重新登錄。其中伺服器上token設置一個有效期,每次APP請求的時候都驗證token和有效期。
那麼我的問題來了:
- 伺服器上的token存儲到資料庫中,每次查詢會不會很費時。如果不存儲到資料庫,應該存儲到哪裡呢。
- 客戶端得到的token肯定要加密存儲的,發送token的時候再解密。存儲到資料庫還是配置文件呢?
token是個易失數據,丟了無非讓用戶重新登錄一下,新浪微博動不動就讓我重新登錄,反正這事兒我是無所謂啦。
所以如果你覺得普通的資料庫表撐不住了,可以放到 MSSQL/MySQL 的記憶體表裡(不過據說mysql的記憶體表性能提升有限),可以放到 Memcache里(講真,這個是挺常見的策略),可以放到redis里(我做過這樣的實現),甚至可以放到 OpenResty 的變數字典里(只要你有信心不爆記憶體)。
token是個憑條,不過它比門票溫柔多了,門票丟了重新花錢買,token丟了重新操作下認證一個就可以了,因此token丟失的代價是可以忍受的——前提是你別丟太頻繁,要是讓用戶隔三差五就認證一次那就損失用戶體驗了。
基於這個出發點,如果你認為用資料庫來保持token查詢時間太長,會成為你系統的瓶頸或者隱患,可以放在記憶體當中。
比如memcached、redis,KV方式很適合你對token查詢的需求。
這個不會太占記憶體,比如你的token是32位字元串,要是你的用戶量在百萬級或者千萬級,那才多少記憶體。
要是數據量真的大到單機記憶體扛不住,或者覺得一宕機全丟風險大,只要這個token生成是足夠均勻的,高低位切一下分到不同機器上就行,記憶體絕對不會是問題。
客戶端方面這個除非你有一個非常安全的辦法,比如操作系統提供的隱私數據存儲,那token肯定會存在泄露的問題。比如我拿到你的手機,把你的token拷出來,在過期之前就都可以以你的身份在別的地方登錄。
解決這個問題的一個簡單辦法
1、在存儲的時候把token進行對稱加密存儲,用時解開。
2、將請求URL、時間戳、token三者進行合併加鹽簽名,服務端校驗有效性。
這兩種辦法的出發點都是:竊取你存儲的數據較為容易,而反彙編你的程式hack你的加密解密和簽名演算法是比較難的。然而其實說難也不難,所以終究是防君子不防小人的做法。話說加密存儲一個你要是被人扒開客戶端看也不會被噴明文存儲……
- 方法1:它拿到存儲的密文解不開、
- 方法2:它不知道你的簽名演算法和鹽,兩者可以結合食用。
但是如果token被人拷走,他自然也能植入到自己的手機裡面,那到時候他的手機也可以以你的身份來用著,這你就瞎了。
於是可以提供一個讓用戶可以主動expire一個過去的token類似的機制,在被盜的時候能遠程止損。
在網路層面上token明文傳輸的話會非常的危險,所以建議一定要使用HTTPS,並且把token放在post body里。
原文鏈接:https://blog.csdn.net/ToBeTheEnder/article/details/52485948