前些天看到 「Token 認證的前因後果」這篇文章,對使用token認證已經講得很清楚了。算法
我也回答過很多關於身份認證的問題,在這裏也簡單總結一下,其實理解其中的核心原理,不管用什麼方案都是相通的。數據庫
先用一個例子來講明一下常規的基於session+cookie的認證過程:segmentfault
1.
客戶端: 我要查看用戶資料 (請求API)
服務端: 你沒有憑證(session_id),請先得到憑證再來,得到憑證須要你提供用戶名密碼。
客戶端: 好的,這是個人用戶名和密碼
服務端: 驗證經過,如今爲你生成憑證,請保管好,之後只認憑證,就算阿貓阿狗拿着你的憑證來查資料,我也會給他。api
服務端生成憑證的同時,會將憑證記錄在案,以便比對。
。。。安全
2.
客戶端: 我要查用戶資料,這是個人憑證(經過cookie傳遞session_id).
服務端: 好的,請稍等,我確認一下你的憑證是否真的(根椐session_id確認session存在且有效) ,OK,是真的,資料拿去。
。。。服務器
3.
客戶端: 我要查用戶資料,這是個人憑證.
服務端: 對不起,你的憑證已通過期失效了,請從新提供用戶名密碼得到新的憑證。cookie
由上面例子能夠看出,整個認證過程的核心是「憑證的生成和驗證」, 那接下來說一下通常狀況下服務端怎麼生成憑證和怎麼驗證憑證:session
session內容通常是用戶的標識信息,好比uid,也有放置更多擴展profile信息以減小查詢數據庫次數的
關聯便是用session_id爲key保存session到文件或數據庫。運維
最近流行一種叫JWT的認證方式,其實也是上面的變種。分佈式
先簡單來看看JWT原理:
a. 服務端驗證經過後,生成憑證(即jwt的token)
b. 請求時帶上token,服務端驗證token有效,驗證經過,返回結果.
若是你看過JWT約定的格式算法,那應該會發現,這個生成過程,實際上只是上面提到的「session_id生成和加密防僞」, 也就是說,JWT是將常規認證簡化了(只生成了憑證,不將憑證記錄在案):
JWT生成憑證時,在憑證中加入了用戶信息(比如是銀行存摺是實名的)
憑證再也不使用cookie傳輸和保存
JWT的內容能夠認爲是明文的,只是增長了數字簽名(至關銀行存摺,蓋上大印防僞)
服務端認證時,無需再查詢,直接根椐內容和簽名,就能確認是否有效。(嗯,銀行看一下存摺,再看一下印章,就認爲存摺是真的,這好像有什麼問題?)
有沒有看出來,jwt只是換了一種說法和約定了內容格式,實際上用cookie也是同樣的效果?
a. 服務端驗證用戶名密碼正確,將用戶ID等必須信息,生成一個字串,而後簽名返回客戶端
b. 客戶端下次請求帶上,服務端根椐簽名確認客戶端有效並從中取得用戶標識來進行相關數據操做。
相對於常規方式,jwt簡化了服務端的認證(從另外一個角度看,實際上是用下降安全性換來的,下文會說明)。
由於http協議自己無狀態,因此才產生出這種的認證過程,但從認證過程能夠看出,因爲服務端只認憑證,這裏面存在必定的安全隱患:
憑證是經過cookie傳遞,並保存在本機,這裏頭有被竊取的風險,因此須要必定的防範措施,好比:
這個很好理解,也就是說我本身造一個憑證出來騙服務器。
再來爲何說jwt下降了安全性?先簡單看看jwt的要點:
不難看出,secret是最關鍵的,一旦secret被獲取或猜出來,那將是災難性的後果,攻擊者能絕不費力的冒充全部用戶,由於用戶標識通常是有規則的(好比是自增的uid),根椐這個標識和有效的jwt格式,拿到secret就能本身生成全部用戶的jwt。
這就是爲何不用純cookie而要用session的緣由之一。
便是說,你就算獲取了個人算法和secret,能夠僞造session_id,但你不知道我有哪些session_id,儘量的減低了風險。實際上更早期的認證方式就是用純cookie的,JWT只是規範了認證的內容,有些文章把JWT說成是新一代的認證我是不認同的。
你可能會說,secret確定要保存好啊,這沒錯,但你有沒想過,總有開發或運維能接觸到secret吧?怎麼防範?
另外,算法知道了,別有用心的人要用窮舉法來猜出secret也是可能的,更可怕的是不少人的secret甚至是一些常見詞語(我甚至看過有人就把「secret」做爲secret的)
最後,假如原來知道secret的同窗離職了,你要修改secret吧? 但全部的token都是根椐舊的secret算出來的,你一改,就全認證失敗了,這在正常業務中也是很難接受的。
session的優勢是更安全,缺點是認證過程較複雜,性能相對較差(須要IO),分佈式很差作,但這些缺點都已有成熟的方案來解決。
jwt的優勢是認證簡單、性能高、自己無狀態無IO依賴自然的支持分佈式隨意擴展。但其缺點是安全風險較大。(這對於大部分帶有敏感操做的站點或API服務是不適合的)
對於jwt的使用,我我的建議: