最近了解下基於 Token 的身份驗證,跟大夥分享下。不少大型網站也都在用,好比 Facebook,Twitter,Google+,Github 等等,比起傳統的身份驗證方法,Token 擴展性更強,也更安全點,很是適合用在 Web 應用或者移動應用上。Token 的中文有人翻譯成 「令牌」,我以爲挺好,意思就是,你拿着這個令牌,才能過一些關卡。javascript
HTTP 是一種沒有狀態的協議,也就是它並不知道是誰是訪問應用。這裏咱們把用戶當作是客戶端,客戶端使用用戶名還有密碼經過了身份驗證,不過下回這個客戶端再發送請求時候,還得再驗證一下。php
解決的方法就是,當用戶請求登陸的時候,若是沒有問題,咱們在服務端生成一條記錄,這個記錄裏能夠說明一下登陸的用戶是誰,而後把這條記錄的 ID 號發送給客戶端,客戶端收到之後把這個 ID 號存儲在 Cookie 裏,下次這個用戶再向服務端發送請求的時候,能夠帶着這個 Cookie ,這樣服務端會驗證一個這個 Cookie 裏的信息,看看能不能在服務端這裏找到對應的記錄,若是能夠,說明用戶已經經過了身份驗證,就把用戶請求的數據返回給客戶端。css
上面說的就是 Session,咱們須要在服務端存儲爲登陸的用戶生成的 Session ,這些 Session 可能會存儲在內存,磁盤,或者數據庫裏。咱們可能須要在服務端按期的去清理過時的 Session 。java
實施 Token 驗證的方法挺多的,還有一些標準方法,好比 JWT,讀做:jot ,表示:JSON Web Tokens 。JWT 標準的 Token 有三個部分:git
中間用點分隔開,而且都會使用 Base64 編碼,因此真正的 Token 看起來像這樣:github
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
header 部分主要是兩部份內容,一個是 Token 的類型,另外一個是使用的算法,好比下面類型就是 JWT,使用的算法是 HS256。web
{
"typ": "JWT", "alg": "HS256" }
上面的內容要用 Base64 的形式編碼一下,因此就變成這樣:算法
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload 裏面是 Token 的具體內容,這些內容裏面有一些是標準字段,你也能夠添加其它須要的內容。下面是標準字段:數據庫
好比下面這個 Payload ,用到了 iss 發行人,還有 exp 過時時間。另外還有兩個自定義的字段,一個是 name ,還有一個是 admin 。json
{
"iss": "ninghao.net", "exp": "1438955445", "name": "wanghao", "admin": true }
使用 Base64 編碼之後就變成了這個樣子:
eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ
JWT 的最後一部分是 Signature ,這部份內容有三個部分,先是用 Base64 編碼的 header.payload ,再用加密算法加密一下,加密的時候要放進去一個 Secret ,這個至關因而一個密碼,這個密碼祕密地存儲在服務端。
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); HMACSHA256(encodedString, 'secret');
處理完成之後看起來像這樣:
SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
最後這個在服務端生成而且要發送給客戶端的 Token 看起來像這樣:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
客戶端收到這個 Token 之後把它存儲下來,下回向服務端發送請求的時候就帶着這個 Token 。服務端收到這個 Token ,而後進行驗證,經過之後就會返回給客戶端想要的資源。
參考:http://blog.csdn.net/sum_rain/article/details/37085771
Token,就是令牌,最大的特色就是隨機性,不可預測。通常黑客或軟件沒法猜想出來。
那麼,Token有什麼做用?又是什麼原理呢?
Token通常用在兩個地方:
二者在原理上都是經過session token來實現的。當客戶端請求頁面時,服務器會生成一個隨機數Token,而且將Token放置到session當中,而後將Token發給客戶端(通常經過構造hidden表單)。下次客戶端提交請求時,Token會隨着表單一塊兒提交到服務器端。
而後,若是應用於「anti csrf攻擊」,則服務器端會對Token值進行驗證,判斷是否和session中的Token值相等,若相等,則能夠證實請求有效,不是僞造的。
不過,若是應用於「防止表單重複提交」,服務器端第一次驗證相同事後,會將session中的Token值更新下,若用戶重複提交,第二次的驗證判斷將失敗,由於用戶提交的表單中的Token沒變,但服務器端session中Token已經改變了。
上面的session應用相對安全,但也叫繁瑣,同時當多頁面多請求時,必須採用多Token同時生成的方法,這樣佔用更多資源,執行效率會下降。所以,也可用cookie存儲驗證信息的方法來代替session Token。好比,應對「重複提交」時,當第一次提交後便把已經提交的信息寫到cookie中,當第二次提交時,因爲cookie已經有提交記錄,所以第二次提交會失敗。
不過,cookie存儲有個致命弱點,若是cookie被劫持(xss攻擊很容易獲得用戶cookie),那麼又一次gameover。黑客將直接實現csrf攻擊。
因此,安全和高效相對的。具體問題具體對待吧。
此外,要避免「加token但不進行校驗」的狀況,在session中增長了token,但服務端沒有對token進行驗證,根本起不到防範的做用。
還需注意的是,對數據庫有改動的增刪改操做,須要加token驗證,對於查詢操做,必定不要加token,防止攻擊者經過查詢操做獲取token進行csrf攻擊。但並非這樣攻擊者就沒法得到token,只是增大攻擊成本而已。