python使用json web token (jwt)實現http api的加密傳輸

lm_y發表於2017-08-22

CSRF攻擊原理圖:


20150119003530_89131.jpg

上圖中Browse是瀏覽器,WebServerA是受信任網站/被攻擊網站A,WebServerB是惡意網站/攻擊網站B。

  • 一開始使用者開啟瀏覽器,訪問受信任網站A,輸入使用者名稱和密碼登陸請求登陸網站A。
  • 網站A驗證使用者資訊,使用者資訊通過驗證後,網站A產生Cookie資訊並返回給瀏覽器。
  • 使用者登陸網站A成功後,可以正常請求網站A。
  • 使用者未退出網站A之前,在同一瀏覽器中,開啟一個TAB訪問網站B。
  • 網站B看到有人方式後,他會返回一些攻擊性程式碼。
  • 瀏覽器在接受到這些攻擊性程式碼後,促使使用者不知情的情況下瀏覽器攜帶Cookie(包括sessionId)資訊,請求網站A。這種請求有可能更新密碼,新增使用者什麼的操作。

    從上面CSRF攻擊原理可以看出,要完成一次CSRF攻擊,需要被攻擊者完成兩個步驟:

    1. 登陸受信任網站A,並在本地生成COOKIE
    2. 在不登出A的情況下,訪問危險網站 B。

    看到這裡,你也許會說:“如果我不滿足以上兩個條件中的一個,我就不會受到CSRF的攻擊”。是的,確實如此,但你不能保證以下情況不會發生:

    1. 你不能保證你登入了一個網站後,不再開啟一個tab頁面並訪問另外的網站。
    2. 你不能保證你關閉瀏覽器了後,你本地的Cookie立刻過期,你上次的會話已經結束。(事實上,關閉瀏覽器不能結束一個會話,但大多數人都會錯誤的認為關閉瀏覽器就等於退出登入/結束會話了……)
    3. 上圖中所謂的攻擊網站,可能是一個存在其他漏洞的可信任的經常被人訪問的網站。

現在常見的csrf防禦是有那麼幾種方式:

  • 一種是在表單加上隨機token串,這種能夠避免99%的CSRF攻擊,還有1%就是首先沒有XSS攻擊。
  • 一種是附加token的基礎上加了refer的來源判斷,
  • 還有一種是XMLHttpRequest的請求的方式,他可以不用在表單裡面加header,但是問題來了,如果你的網站以前經常用的時動態載入的資料,也就是ajax方式載入的,那麼很容易用XMLHttpRequest在請求體裡面加上先前respone返回token
  • 每次表單請求都帶驗證碼,對於使用者體驗這是萬萬不能的。我相信會讓使用者瘋掉的。

現在我們來看看HTTP api有哪幾種認證方式,首先要明白,認證和鑑權是不同的。認證是判定使用者的合法性,鑑權是判定使用者的許可權級別是否可執行後續操作。這裡所講的僅含認證。認證有如下幾種方法:

  1. 第一個是使用在HTTP規範中的Basic Auth,這個配置也是相當的簡單,原理是在每個請求的header中新增使用者名稱和密碼的字串(格式為“username:password”,用base64編碼)。但是這種方式安全性較低,就是簡單的將使用者名稱和密碼base64編碼放到header中。 base64編碼前:Basic admin:adminbase64編碼後:Basic YWRtaW46YWRtaW4=放到Header中:Authorization: Basic YWRtaW46YWRtaW4=。正是因為是簡單的base64編碼儲存,切記切記在這種方式下一定得注意使用ssl,不然就是裸奔了。 在某些產品中也是基於這種類似方式,只是沒有使用apache的basic機制,而是自己寫了認證框架,原理還是一樣的,在一次請求中base64解碼Authorization欄位,再和認證資訊做校驗。很顯然這種方式有問題,認證資訊相當於明文傳輸,另外也沒有防暴力破解功能。

  2. 第二個API Key是客戶端從服務端簽收一個加密的key,然後自己通過一定的演算法組合加密資料,服務端會根據你的來源解析key。類似:http://example.com/api?key=dfkaj134

client


Paste_Image.png

Server


Paste_Image.png

client端向服務端註冊,服務端給客戶端傳送響應的api_key以及security_key,注意儲存不要洩露,然後客戶端根據api_key,secrity_key,timestrap,rest_uri採用hmacsha256演算法得到一個hash值sign,構造途中的url傳送給服務端。 服務端收到該請求後,首先驗證api_key,是否存在,存在則獲取該api_key的security_key,接著驗證timestrap是否超過時間限制,可依據系統成而定,這樣就防止了部分重放攻擊,途中的rest_api是從url獲取的為/rest/v1/interface/eth0,最後計算sign值,完之後和url中的sign值做校驗。這樣的設計就防止了資料被篡改。 通過這種API Key的設計方式加了時間戳防止了部分重放,加了校驗,防止了資料被篡改,同時避免了傳輸使用者名稱和密碼,當然了也會有一定的開銷。

3 第三種是OAuth(或者OAuth2)。OAuth協議適用於為外部應用授權訪問本站資源的情況。其中的加密機制與HTTP Digest身份認證相比,安全性更高。使用和配置都比較複雜,這裡就不涉及了。

4 第四種就是Token的機制。 在各種客戶端上每次都讓使用者提交使用者名稱和密碼,這有些不合理的。 通常的情況是客戶端通過一些可靠資訊和伺服器交換取token,這個token作為客服端再次請求的許可權鑰匙,當然token也是存在有效時間控制的。 Token通常比密碼更加長而且複雜。那麼一旦獲得了token,在每次呼叫API的時候都要附加上它。這仍然比直接傳送賬戶和密碼更加安全,哪怕是HTTPS。把token想象成一個安全的護照。你在一個安全的前臺驗證你的身份(通過你的使用者名稱和密碼),如果你成功驗證了自己,你就可以取得這個。當你走進大樓的時候(試圖從呼叫API獲取資源),你會被要求驗證你的護照,而不是去前臺重新驗證。

5 第五種,JWT協議似乎已經應用十分廣泛,JSON Web Token——一種基於token的json格式web認證方法。JWT是一段被base64url編碼過的字元序列,並用點號分隔。它由三部分組成,頭部header、載荷playload與簽名sign。 服務端和客戶端都可以通過secret_key來識別資訊是否被串改過。其基本的原理是,第一次認證通過使用者名稱密碼,服務端簽發一個json格式的token。後續客戶端的請求都攜帶這個token,服務端僅需要解析這個token,來判別客戶端的身份和合法性。在這裡JWT是用來取代服務端的Session而非客戶端Cookie的方案,當 然對於客戶端本地儲存,HTML5提供了Cookie之外更多的解決方案(localStorage/sessionStorage),究竟採用哪種儲存 方式,其實從Js操作上來看沒有本質上的差異,不同的選擇更多是出於安全性的考慮。

具體演算法如下圖:


Paste_Image.png
JWT的主要應用場景

身份認證

在這種場景下,一旦使用者完成了登陸,在接下來的每個請求中包含JWT,可以用來驗證使用者身份以及對路由,服務和資源的訪問許可權進行驗證。由於它的開銷非常小,可以輕鬆的在不同域名的系統中傳遞,所有目前在單點登入(SSO)中比較廣泛的使用了該技術。

資訊交換

在通訊的雙方之間使用JWT對資料進行編碼是一種非常安全的方式,由於它的資訊是經過簽名的,可以確保傳送者傳送的資訊是沒有經過偽造的。



作者:Moc木殼
連結:http://www.jianshu.com/p/6b6dc558353a
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關文章