關於Tokens你需要知道的10件事

原文鏈接:Here

原作者:Matias Woloski

幾周前我們發表了一篇短文《cookies與tokens在單頁應用中的對比》(主要以AngularJs應用爲例)。社區裏對這個話題很感興趣,於是我們接着發表了第二篇《在socket.io等實時框架中基於Token的認證》。趁着大家對這個話題還保持着熱情,我們決定再寫一篇文章進一步探討基於Token認證的常見問題。我們開始吧~

1.Tokens需要保存在Local Storage、Session Storage或Cookies中

在Tokens被應用於單頁應用的背景下,有人提出了問題:在瀏覽器中刷新頁面時,token會發生什麼變化。答案很簡單:你需要將token保存在Local Storage、Session Storage或客戶端內置的Cookies中,在瀏覽器不支持Session Storage的情況下,它會被polyfills爲cookies。

你或許想問“但如果我將token保存在cookie的話,豈不是很危險”。其實不然,這種情況下,你使用的cookies只是作爲存儲機制而非驗證機制(即是說,web框架不會使用cookie來驗證用戶,因此不存在XSRF攻擊的危險)

2.Tokens像Cookies一樣會過期,但你有更多的控制權

Tokens具有生命週期(在JSON Web Tokens中由exp屬性控制),否則用戶就可以登錄一次卻永遠無需認證了。Cookies由於相同的原因也具有生命週期。

在Cookies中,如下不同情況生命週期也不一樣:

1.當關閉瀏覽器時,Cookies會被銷燬(如Session Cookies)

2.你也可以實現一個服務端檢查機制(通常由Web框架幫你完成),你可以設置生命週期或滑動窗口生命週期。

3.Cookies在一段時間內可以是永久的(即使關閉瀏覽器也不會被銷燬)

在Tokens中,一旦過期,你只需要獲取一個新的token。你可以寫一個端點來更新token:

1.驗證舊的token

2.檢查用戶是否還處於登錄狀態或者在訪問你的網站

3.產生一個重新續時的新token

你甚至可以將token生成的時間寫入其中,並在大約兩週後強制用戶重新登錄。

3.Local/Session Storage無法跨域,請使用Cookies作標記

如果你將cookie的作用域名設置爲.yourdomain.com,那麼它可以在yourdomain.comapp.yourdomain.com中被訪問。如果用戶在主域登錄卻被重定向到app.yourdomain.com,要驗證cookie也是很方便的。

Tokens存儲在local/session storage中,這意味着不同域名之間是無法相互訪問的(即使是子域名)。那麼你該怎麼做呢?

其中一種做法是,當用戶在app.yourdomain.com中驗證完畢後,你生成一個token並設置一個作用域名爲.yourdomain.com的Cookie標記用戶已經登錄。


然後,你可以在yourdomain.com驗證cookie的存在並重定向到app.yourdomain.com。而Token可以在app的子域中使用(如果token依然合法)。

可能會出現cookie存在而token已經被刪除的情況。這種情況下,用戶必須重新登錄。這裏需要強調的是,正如我們之前所說,我們並不將cookie當作驗證機制,而僅僅把它作爲能夠跨域保存信息的存儲機制。

4.每個CORS請求都會先發一個預請求

有人指出,Authorization報頭並非一個簡單的報頭,因此在向特定URLs發送請求前都需要發送一個預請求。


這時你需要發送Content-Type: application/json

提醒下,OPTIONS請求自身並沒有Authorization報頭信息,所以你的web框架需要對OPTIONS和後續的請求作一些處理(提示:微軟的IIS因爲某些原因在這方面存在一些問題)。

5.當你處理流媒體時,請用token獲取簽名請求

在使用cookies時,你可以輕易地觸發文件下載和一些文本流。然而,在tokens中,是通過XHR來完成請求的,你無法依賴於此。解決的辦法就是像AWS那樣生成一個簽名請求,例如,Hawk Bewits就是一個支持該方法的優秀框架:

請求:


迴應:

其中,ticket是無狀態的。它通過URL: host + path + query + headers + timestamp + HMAC來生成,並帶有過期時間。所以它能在一段時間內(比如5分鐘)被用來下載文件。

你會被重定向到/download-file/123?ticket=lahdoiasdhoiwdowijaksjdoaisdjoasidja。服務器將驗證ticket是否合法並完成接下來的業務操作。

6.比起XSRF,處理XSS較爲容易

Cookies具有允許設置HttpOnly標記的特性,它可以只允許服務器訪問而非JavaScript。這很有用,因爲它保護Cookies不被客戶端代碼注入攻擊(XSS)。

由於tokens被存儲在local/Session Storage或者客戶端內置的Cookie中,這容易遭受XSS攻擊並被攻擊者獲取到token。這是個令人擔憂的問題,因此你需要將tokens的生存時間設置得短一點。

Cookies層面上,一種主要的攻擊是XSRF。真實情況是,XSRF是最讓人忽略的攻擊之一。普通的開發者可能甚至不瞭解這種風險,因此很多應用缺少反XSRF攻擊的機制。然而,每個人都知道注入是什麼。簡單地說,如果你允許在不轉義的情況下渲染用戶輸入的內容,那麼你的應用就暴露在XSS攻擊之下了。根據我們的經驗,防範XSS比XSRF容易。因爲並非所有的web框架都內置了反XSRF機制,而在絕大多數支持轉義語法的模板引擎中,防範XSS卻是容易得多。

7.每次請求都需要發送token,請注意它的大小

當你每發送一次API請求,都需要將token附加到Authorization頭部中發出去。


和Cookies的比較

token的大小取決於你將多少信息存在裏面了,這可能會很大。相比起來,Session Cookies只保存一個標記(connect.sid,PHPSESSID等等),主體內容被保存在服務端(僅有一臺服務器就保存在內存,在服務器羣中則保存在數據庫)。

現在,你完全可以實現一個類似tokens的機制。這個token擁有你需要的基本信息,在服務端中根據每次API的調用,你都可以爲token補充更多的信息。Cookies的確也能做到這樣,但不同的是tokens有一個好處,你可以完全控制它,畢竟它是你代碼的一部分。


在服務端中:

值得注意的是,你可以完整地將Session保存在Cookie中(而不僅僅是一個標記)。但並不是所有的Web平臺都支持這麼做,舉個例子,在Node.js中,你可以使用mozilla/node-client-sessions

8.如果存儲敏感信息,請對token加密

Token的簽名能夠防止信息被篡改,TLS/SSL能夠防止中間人攻擊。但如果包含了用戶的敏感信息(身份證號等),你就需要對它進行加密。JWT(JSON Web Tokens)用JWE(JSON Web Encryption)作爲規範,但大多數類庫都還沒有實現JWE,所以最簡單的做法就是像下面那樣使用AES-CBC模式進行加密。


當然,你也可以像#7那樣,將敏感信息保存在數據庫中。

9.JSON Web Tokens可以在OAuth中使用

Tokens往往和OAuth聯繫在一起。OAuth2是一種解決身份認證授權的協議。經過用戶同意授權訪問自己的數據後,認證服務器會返回一個access_token,這樣可以使用用戶的身份訪問對應的APIs。

通常這些tokens是不透明的。他們被稱之爲bearertokens,並且以隨機字符串保存到某種類型的哈希表中,並存儲在服務器裏(數據庫、緩存等)。內容包括過期時間、請求範圍(例如訪問好友列表)以及授權的用戶。然後當API被調用時,token會被髮送給服務器,服務器會在哈希表中查找信息並開始驗證(比如token是否已過期,是否超出請求範圍)。

這種token和我們一直討論的簽名token(如JWT)的主要區別是,後者是無狀態的,它們並不需要存儲在哈希表中,因此它是一種更輕量級的方法。OAuth2並沒有規定access_token的格式,所以你可以返回一個經授權服務器包含的帶有“請求範圍、權限列表和過期時間”的JWT。

10.Tokens不是萬能的,請仔細考慮授權使用場景

幾年前,我們爲一家大公司實施開發基於token的架構。這是一個有大量信息需要被保護的擁有超過10萬名員工的公司。他們想要實現一個基於“身份驗證和授權”的集中式管理組織系統。試想想“用戶X可以讀取W地區裏Z醫院的臨牀試驗Y的ID和名稱”的應用場景。這種細粒度的授權,你可以想像,不管是在技術還是管理上,都是很難處理的。

  • Tokens會變得很大
  • 你的apps/APIs會變得很複雜
  • 不管是讓誰來授予權限都是很難進行下去的

站在信息架構的角度上,爲確保創建合理的作用範圍和權限,我們放棄了這個工作。

結論:要抵制把一切東西都轉換成tokens的誘惑,在使用這種方式時請務必先做好各種分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章