爲了解決Http無狀態問題,產生了cookie和session技術。python
傳統的session技術解決了無狀態問題,可是不能防止客戶端的篡改,並且對於服務端要保存session,在數據量較大,業務規模增長時,還要解決多臺服務器之間的session共享問題,使用redis或者memcached等方案。redis
產生可JWT技術能夠解決用戶篡改問題,服務器端產生的標識,使用算法加密,對標識簽名。算法
再次收到服務器端的標識,就要檢查簽名。瀏覽器
這種方法在加密解密時,會消耗cpu計算資源,並且沒法讓瀏覽器本身檢查過時數據,而且刪除。安全
下邊我將嘗試解釋一下jwt防篡改的原理。服務器
JWT 全稱(Json WEB Token)是一種採用Json方式安裝傳輸信息的方式。cookie
python下的實現的pyjwtsession
文檔 : https://pyjwt.readthedocs.io/en/latest/memcached
安裝 : pip install pyjwt測試
先看如下代碼:
import jwt key = "secret" token = jwt.encode({"test": "100"},key,"HS256") print(token) header,payload,signature = token.split(b".") print(header) print(payload) print(signature)
顯示
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZXN0IjoiMTAwIn0.p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8' b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9' b'eyJ0ZXN0IjoiMTAwIn0' b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'
能夠知道JWT由3段由點分割的部分組成。
它使用的編碼是base64編碼,咱們導入如下
import jwt key = "secret" token = jwt.encode({"test": "100"},key,"HS256") print(token) header,payload,signature = token.split(b".") import base64 def equal(b: bytes): """用來補齊被JWT去掉的等號""" rest = len(b) % 4 return b + b'=' * rest print("header=",base64.urlsafe_b64decode(equal(header))) print("payout=", base64.urlsafe_b64decode(equal(payload))) print("signature", base64.urlsafe_b64decode(equal(signature)))
顯示:
header= b'{"typ":"JWT","alg":"HS256"}' payout= b'{"test":"100"}' signature b'\xa7gA\xb2L\xac\xb6lN\x94\x85\xeb\x04*0\xbb\xa0\xcfqd\x1bF\xb6LOxIW\xb8\x8cc\xef'
能夠看到,JWT中傳輸的token內容由三部分組成
下邊是源碼中的一部分,signing_input就是將前兩部分轉爲JSON格式,再使用base64編碼,鏈接起來,傳入下邊的方法中,alg_obj是方法,key是預處理key
signing_input = b'.'.join(segments) try: alg_obj = self._algorithms[algorithm] key = alg_obj.prepare_key(key) signature = alg_obj.sign(signing_input, key)
咱們模仿一下,可得
import jwt # Create your tests here. key = "secret" token = jwt.encode({"test": "100"},key,"HS256") header,payload,signature = token.split(b".") print(signature) import base64 # def equal(b: bytes): # """用來補齊被JWT去掉的等號""" # rest = len(b) % 4 # return b + b'=' * rest # print("header=",base64.urlsafe_b64decode(equal(header))) # print("payout=", base64.urlsafe_b64decode(equal(payload))) # print("signature", base64.urlsafe_b64decode(equal(signature))) from jwt import algorithms alg = algorithms.get_default_algorithms()["HS256"] newkey = alg.prepare_key(key) signature_input = b".".join([header,payload]) signature = alg.sign(signature_input,newkey) print(base64.urlsafe_b64encode(signature))
顯示,能夠看到
b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'
b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8='
因此在密碼相同時,傳輸相同的信息,獲得的值是同樣的。
密碼要足夠強,且要足夠安全。能夠在測試下改變內容,看簽名會不會改變。
import jwt # Create your tests here. key = "secret" token = jwt.encode({"test": "100"},key,"HS256") header,payload,signature = token.split(b".") print(signature) import base64 # def equal(b: bytes): # """用來補齊被JWT去掉的等號""" # rest = len(b) % 4 # return b + b'=' * rest # print("header=",base64.urlsafe_b64decode(equal(header))) # print("payout=", base64.urlsafe_b64decode(equal(payload))) # print("signature", base64.urlsafe_b64decode(equal(signature))) token = jwt.encode({"test": "1000"},key,"HS256") # 改變payload內容 header,payload,signature = token.split(b".") from jwt import algorithms alg = algorithms.get_default_algorithms()["HS256"] newkey = alg.prepare_key(key) signature_input = b".".join([header,payload]) signature = alg.sign(signature_input,newkey) print(base64.urlsafe_b64encode(signature))
能夠看到簽名變了
b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8' b'uCmPr1eOuLz8IDLQfN8t_DsyrB9PYfdvdueeHSBWN04='
通過以上測試,能夠知道,數據在使用JWT傳輸時,是明文傳輸的,注意不要傳輸敏感數據。
JWT的防篡改還可使用公鑰,私鑰,來防止用戶被劫持的可能性。
在用戶登錄成功後可使用JWT技術,登陸後給用戶JWT,用戶發請求時加上jwt,服務器校驗簽名,經過就容許訪問,在單點登錄時普遍應用。