Web認證及API的 使用TOKEN的一些思考

首先貼一下看過的文章:
1.http://www.cnblogs.com/xiekel...
2.http://blog.leapoahead.com/20...
3.http://blog.leapoahead.com/20...
4.jwt demo :https://github.com/bigmeow/JWT
5.https://github.com/jwtk/jjwt 這裏面有幾篇比較好的算是官方推薦的
6.http://blog.csdn.net/koastal/... 基於timestamp和nonce的防止重放攻擊方案html

公司目前的WEB設計都是基於HTTP Basic Auth,一直以爲會有很大的安全問題,重放攻擊就很簡單實現。git

引用第一篇文章的一段話:HTTP Basic Auth簡單點說明就是每次請求API時都提供用戶的username和password,簡言之,Basic Auth是配合RESTful API 使用的最簡單的認證方式,只需提供用戶名密碼便可,但因爲有把用戶名密碼暴露給第三方客戶端的風險,在生產環境下被使用的愈來愈少。所以,在開發對外開放的RESTful API時,儘可能避免採用HTTP Basic Auth。github

以爲採用TOKEN的方式實現WEB和API的認證。 JSON WEB TOKEN 算是比較成熟的解決方案,所以採用JSON WEB TOKEN。 JSON WEB TOKEN的基本介紹請看 文章開頭的後面3個鏈接。 數據庫

JWT解決了:
1.做爲TOKEN驗證使用時解決了用戶直接輸入帳號和密碼的進行認證的問題。
2.部分數據安全傳輸的問題(例如第2個連接的文章,是添加關注,服務器生成的鏈接,能夠安全的經過郵件發送給目標客戶,而不暴露操做用戶的相關信息)。 json

做爲TOKEN使用,JWT的payload須要有關於用戶信息的字段,否則怎麼知道是哪一個用戶在操做,通常不要填寫敏感信息,如用戶密碼等,由於是經過base64編碼,是能夠破解的。用戶登陸和獲取TOKEN的接口是須要HTTPS加密的,不然用戶帳號和密碼是會暴露的,也就沒有什麼安全性可言了。緩存

請求時TOKEN的上傳能夠用如下方式:
1.經過cookie
2.經過HTTP Authorization Head中
3.GET/POST方法,直接經過參數形式。安全

安全性:
1.首先要保證登陸和得到TOKEN的接口須要HTTPS加密
2.防止重放攻擊:目前想到的 客戶端和服務器間有一個共享的祕鑰,在調用API時須要將API的方法、參數、TOKEN作一次簽名(可用jwt)。服務器首先驗證方法、參數、TOKEN的簽名是否正確,而後驗證TOKEN的簽名是否正確。第一次簽名時保證即便請求被劫持,劫持者也沒有辦法假冒其它請求或者修改參數,在必定程度上保證了安全性。 第二次簽名驗證主要是驗證TOKEN的有效性,驗證用戶身份。服務器

以上步驟須要服務器上保存兩種祕鑰,第一種是生產TOKEN的祕鑰,這個只有服務器程序知道。第二種祕鑰是針對每一個使用接口的開發者的共享祕鑰,這個祕鑰只須要服務器和開發者知道(開發者能夠登陸網站,在申請使用接口時,自定義本身的共享祕鑰)。cookie

3.共享祕鑰的保存:共享祕鑰須要安全的保存,不能被泄漏。koa

-----------------------如下拷貝自第6個連接------------------------------------------
之前老是經過timestamp來防止重放攻擊,可是這樣並不能保證每次請求都是一次性的。今天看到了一篇文章介紹的經過nonce(Number used once)來保證一次有效,感受二者結合一下,就能達到一個很是好的效果了。

重放攻擊是計算機世界黑客經常使用的攻擊方式之一,所謂重放攻擊就是攻擊者發送一個目的主機已接收過的包,來達到欺騙系統的目的,主要用於身份認證過程。
首先要明確一個事情,重放攻擊是二次請求,黑客經過抓包獲取到了請求的HTTP報文,而後黑客本身編寫了一個相似的HTTP請求,發送給服務器。也就是說服務器處理了兩個請求,先處理了正常的HTTP請求,而後又處理了黑客發送的篡改過的HTTP請求。

基於timestamp的方案

每次HTTP請求,都須要加上timestamp參數,而後把timestamp和其餘參數一塊兒進行數字簽名。由於一次正常的HTTP請求,從發出到達服務器通常都不會超過60s,因此服務器收到HTTP請求以後,首先判斷時間戳參數與當前時間相比較,是否超過了60s,若是超過了則認爲是非法的請求。

假如黑客經過抓包獲得了咱們的請求url:
http://koastal.site/index/Inf...
其中

$sign=md5($uid.$token.$stime);
// 服務器經過uid從數據庫中可讀出token

通常狀況下,黑客從抓包重放請求耗時遠遠超過了60s,因此此時請求中的stime參數已經失效了。
若是黑客修改stime參數爲當前的時間戳,則sign參數對應的數字簽名就會失效,由於黑客不知道token值,沒有辦法生成新的數字簽名。

但這種方式的漏洞也是顯而易見的,若是在60s以內進行重放攻擊,那就沒辦法了,因此這種方式不能保證請求僅一次有效。

基於nonce的方案

nonce的意思是僅一次有效的隨機字符串,要求每次請求時,該參數要保證不一樣,因此該參數通常與時間戳有關,咱們這裏爲了方便起見,直接使用時間戳的16進制,實際使用時能夠加上客戶端的ip地址,mac地址等信息作個哈希以後,做爲nonce參數。
咱們將每次請求的nonce參數存儲到一個「集合」中,能夠json格式存儲到數據庫或緩存中。
每次處理HTTP請求時,首先判斷該請求的nonce參數是否在該「集合」中,若是存在則認爲是非法請求。

假如黑客經過抓包獲得了咱們的請求url:
http://koastal.site/index/Inf...

其中

$sign=md5($uid.$token.$nonce);
// 服務器經過uid從數據庫中可讀出token

nonce參數在首次請求時,已經被存儲到了服務器上的「集合」中,再次發送請求會被識別並拒絕。
nonce參數做爲數字簽名的一部分,是沒法篡改的,由於黑客不清楚token,因此不能生成新的sign。

這種方式也有很大的問題,那就是存儲nonce參數的「集合」會愈來愈大,驗證nonce是否存在「集合」中的耗時會愈來愈長。咱們不能讓nonce「集合」無限大,因此須要按期清理該「集合」,可是一旦該「集合」被清理,咱們就沒法驗證被清理了的nonce參數了。也就是說,假設該「集合」平均1天清理一次的話,咱們抓取到的該url,雖然當時沒法進行重放攻擊,可是咱們仍是能夠每隔一天進行一次重放攻擊的。並且存儲24小時內,全部請求的「nonce」參數,也是一筆不小的開銷。

基於timestamp和nonce的方案

那咱們若是同時使用timestamp和nonce參數呢?
nonce的一次性能夠解決timestamp參數60s的問題,timestamp能夠解決nonce參數「集合」愈來愈大的問題。

咱們在timestamp方案的基礎上,加上nonce參數,由於timstamp參數對於超過60s的請求,都認爲非法請求,因此咱們只須要存儲60s的nonce參數的「集合」便可。

假如黑客經過抓包獲得了咱們的請求url:
http://koastal.site/index/Inf...

其中

$sign=md5($uid.$token.$stime.$nonce);
// 服務器經過uid從數據庫中可讀出token

若是在60s內,重放該HTTP請求,由於nonce參數已經在首次請求的時候被記錄在服務器的nonce參數「集合」中,因此會被判斷爲非法請求。超過60s以後,stime參數就會失效,此時由於黑客不清楚token的值,因此沒法從新生成簽名。

綜上,咱們認爲一次正常的HTTP請求發送不會超過60s,在60s以內的重放攻擊能夠由nonce參數保證,超過60s的重放攻擊能夠由stime參數保證。

由於nonce參數只會在60s以內起做用,因此只須要保存60s以內的nonce參數便可。

咱們並不必定要每一個60s去清理該nonce參數的集合,只須要在新的nonce到來時,判斷nonce集合最後一次修改時間,超過60s的話,就清空該集合,存放新的nonce參數集合。其實nonce參數集合能夠存放的時間更久一些,可是最少是60s。

驗證流程

//判斷stime參數是否有效
if( $now - $stime > 60){

die("請求超時");

}
//判斷nonce參數是否在「集合」已存在
if( in_array($nonce,$nonceArray) ){

die("請求僅一次有效");

}
//驗證數字簽名
if ( $sign != md5($uid.$token.$stime.$nonce) ){

die("數字簽名驗證失敗");

}
//判斷是否須要清理nonce集合
if( $now - $nonceArray->lastModifyTime > 60 ){

$nonceArray = null;

}
//記錄本次請求的nonce參數
$nonceArray.push($nonce);

//開始處理合法的請求

相關文章
相關標籤/搜索