前言
本文將首先概述基於cookie的身份驗證方式和基於token的身份驗證方式,在此基礎上對兩種驗證進行比較。
最後將介紹JWT(主要是翻譯官網介紹)。
概述
HTTP是一個“無狀態”協議,這意味着Web應用程序服務器在響應客戶端請求時不會將多個請求鏈接到任何一個客戶端。然而,許多Web應用程序的安全和正常運行都取決於系統能夠區分用戶並識別用戶及其權限。
這就需要一些機制來爲一個HTTP請求提供狀態。它們使站點能夠在會話期間對各用戶做出適當的響應,從而保持跟蹤用戶在應用程序中的活動(請求和響應)。
cookie和token
下面兩圖大致展示了基於cookie和基於token工作流程。
基於cookie的身份驗證
cookie是源自站點並由瀏覽器存儲在客戶計算機上的簡單文件。它們通常包含一個名稱和一個值,用於將客戶端標識爲對站點具有特定許可權的特定用戶。
cookie與源域相連接的方式可以確保僅源域能夠訪問其中存儲的信息。第三方服務器既不能讀取也不能更改用戶計算機上該域的cookie內容。
網景公司的前僱員於1993年發明了cookie。
基於cookie的驗證是有狀態的,就是說驗證或者會話信息必須同時在客戶端和服務端保存。這個信息服務端一般在數據庫中記錄,而前端會保存在cookie中。
驗證的一般流程如下:
- 用戶輸入登陸憑據;
- 服務器驗證憑據是否正確,並創建會話,然後把會話數據存儲在數據庫中;
- 具有會話id的cookie被放置在用戶瀏覽器中;
- 在後續請求中,服務器會根據數據庫驗證會話id,如果驗證通過,則繼續處理;
- 一旦用戶登出,服務端和客戶端同時銷燬該會話。
基於token的身份驗證
隨着單頁面應用程序的流行,以及Web API和物聯網的興起,基於token的身份機制越來越被大家廣泛採用。
當討論基於token的身份驗證時,一般都是說的JSON Web Tokens(JWT)。雖然有着很多不同的方式實現token,但是JWT已經成爲了事實上的標準,所以後面會將JWT和token混用。
基於token的驗證是無狀態的。服務器不記錄哪些用戶已登陸或者已經發布了哪些JWT。對服務器的每個請求都需要帶上驗證請求的token。該標記既可以加在header中,可以在POST請求的主體中發送,也可以作爲查詢參數發送。
工作流程如下:
- 用戶輸入登陸憑據;
- 服務器驗證憑據是否正確,然後返回一個經過簽名的token;
- 客戶端負責存儲token,可以存在local storage,或者cookie中;
- 對服務器的請求帶上這個token;
- 服務器對JWT進行解碼,如果token有效,則處理該請求;
- 一旦用戶登出,客戶端銷燬token。
token相對cookie的優勢
無狀態
基於token的驗證是無狀態的,這也許是它相對cookie來說最大的優點。後端服務不需要記錄token。每個令牌都是獨立的,包括檢查其有效性所需的所有數據,並通過聲明傳達用戶信息。
服務器唯一的工作就是在成功的登陸請求上籤署token,並驗證傳入的token是否有效。
防跨站請求僞造(CSRF)
舉個CSRF攻擊的例子,在網頁中有這樣的一個鏈接![](http://bank.com?withdraw=1000&to=tom)
,假設你已經通過銀行的驗證並且cookie中存在驗證信息,同時銀行網站沒有CSRF保護。一旦用戶點了這個圖片,就很有可能從銀行向tom這個人轉1000塊錢。
但是如果銀行網站使用了token作爲驗證手段,攻擊者將無法通過上面的鏈接轉走你的錢。(因爲攻擊者無法獲取正確的token)
多站點使用
cookie綁定到單個域。foo.com域產生的cookie無法被bar.com域讀取。使用token就沒有這樣的問題。這對於需要向多個服務獲取授權的單頁面應用程序尤其有用。
使用token,使得用從myapp.com獲取的授權向myservice1.com和myservice2.com獲取服務成爲可能。
支持移動平臺
好的API可以同時支持瀏覽器,iOS和Android等移動平臺。然而,在移動平臺上,cookie是不被支持的。
性能
一次網絡往返時間(通過數據庫查詢session信息)總比做一次HMACSHA256計算的Token驗證和解析要費時得多。
JWT
JWT是JSON Web Token的縮寫。它定義了一種緊湊且獨立的方式,用於將各方之間的信息安全地傳輸爲JSON對象。這是一個開放的標準,見RFC 7519。
基於JWT的信息可以通過數字簽名進行校驗。校驗的方法即可以使用消息摘要(HMAC),或者非對稱加密(RSA)。
JWT具有兩個特點:
- 緊湊。由於其較小的尺寸,JWT可以通過URL,POST參數或者HTTP頭髮送。較小的尺寸會帶來傳輸速度的優勢;
- 自包含:token中包含了用戶的所有必須信息,避免了多次查詢數據庫的需要。
應用場景
以下是JWT有用的一些場景
- 驗證:這是JWT最常用的場景。一旦用戶登陸成功,每個後續的請求將包括JWT,服務器在對JWT進行驗證後,允許用戶訪問服務和資源。單點登陸是一個廣泛使用JWT的場景,因爲它的開銷相對較小,並且能夠在不同的域中輕鬆使用。
- 信息交換:JWT是在可以安全地傳輸信息。因爲JWT可以被簽名,收信人可以確認發信人的身份,同時也能夠驗證內容是否被篡改。
格式
JWT包括三個部分:頭部、載荷和簽名,這三個部分通過.
連接起來。
因此,一個典型的JWT長這樣xxxxx.yyyyy.zzzzz
。
頭部
頭部通常包括兩部分:token類型(JWT),和使用到的算法,如HMAC、SHA256或RSA,下面是一個例子,說明這是一個JWT,使用的簽名算法是HS256。
{
"alg": "HS256",
"typ": "JWT"
}
頭部會通過Base64Url編碼形成JWT的第一部分
載荷
第二部分是載荷,要傳遞出去的聲明,其中包含了實體(通常是用戶)和附加元數據。有三種類型的聲明:
- 保留聲明:這是一組預定義的聲明,非強制性,用來幫助接收方(服務器)更好地理解這個JWT。其中包括:iss(issuer,該JWT的簽發者),exp(expiration time,過期時間),sub(subject,該JWT所面向的用戶),aud(audience,JWT的接收者),和另外一些聲明
- 公共聲明:這些可以用使用JWT的人隨意定義。但是爲了避免衝突,應在在IANA JSON WEB令牌註冊表中定義它們,或者將其定義爲包含防衝突命名空間的URI。
- 私有聲明:這些是爲了在同意使用它們的各方之間共享信息而創建的自定義聲明。
下面是一個例子
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
載荷會通過Base64Url編碼形成JWT的第二部分
簽名
將上面兩部分編碼後,使用.
連接在一起,形成了xxxxx.yyyyyy。
最後,採用頭部指定的算法,和私鑰對上面的字符串進行簽名。
加入採用的是HMAC SHA256 算法,簽名將通過下面的方式生成
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
該簽名用戶驗證JWT發送者的身份,並確保該消息沒有被篡改。
JWT工作流程
在身份驗證過程中,一旦用戶使用其憑據成功登陸,服務器將返回JWT,該JWT必須在客戶端本地保存。這和服務器創建會話並返回cookie的傳統方法不同。
每次用戶要請求受保護的資源時,必須在請求中帶上JWT。通常在Authorization頭Bearer中,如下:
Authorization: Bearer <token>
這是一種無狀態的認證機制,因爲用戶狀態永遠不會保存在服務器內存中。服務器的受保護路由將在授權頭中檢查有效的JWT,如果存在,則允許用戶訪問受保護的資源。由於JWT是自說明的,包含了所有必要的信息,這就減少了多次查詢數據庫的需要。
這樣可以完全依賴無狀態的數據API,甚至可以向下遊服務發出請求。API的作用域並不重要,因此跨源資源共享(CORS)不會是一個問題,因爲它不使用Cookie。
整個流程如下圖:
使用JWT的理由
現在來談談JWT與簡單網頁令牌(SWT)和安全斷言標記語言令牌(SAML)相比的優勢。
由於JSON比XML更短小,編碼時其大小也較小,使得JWT比SAML更緊湊。這使得JWT成爲在HTML和HTTP環境中能更快地傳遞。
從安全角度來說,SWT只能通過使用HMAC算法的共享密鑰進行對稱簽名。但是,JWT和SAML令牌可以以X.509證書的形式使用公鑰/私鑰對進行簽名。與簡單的JSON簽名相比,使用XML數字簽名簽名XML而不引入模糊的安全漏洞是非常困難的。
JSON解析器在大多數編程語言中很常見,因爲它們直接映射到對象。相反,XML沒有自然的文檔對對象映射。這使得使用JWT比SAML斷言更容易。
從使用平臺來說,JWT在Internet規模上使用。這突出了客戶端處理多個平臺上特別是移動平臺上的JSON Web令牌的便利性。
作者:黃索遠
鏈接:http://www.jianshu.com/p/ce9802589143
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。