驗簽:
背景:
在實際工作中,有些敏感接口如支付接口,接口定義了一個入參為auth,在請求接口時,必須傳入正確的auth,接口才會返回正確的數據,否則不處理,目的是為了加強接口的安全性
原理:
每次發送請求時都需要攜帶一個參數,可能是header里面傳,也可能是在body里面,一般定義名為auth
根據提供的算法,生成一個簽名,每次請求的時候帶上這個簽名,后端驗證簽名通過后,這個請求才會被處理,否則不處理這條請求
例子:
使用fastapi本地mock一個接口
import fastapi import uvicorn import hashlib server = fastapi.FastAPI() salt = 'ssz-abc' @server.post('/api/test') def test(name:str,addr:str,phone:str,auth:str): s = '%s%s%s%s'%(name,addr,phone,salt) s = hashlib.md5(s.encode()).hexdigest() print(s) if auth == s: return {"code":0,"msg":"操作成功","name":name,"addr":addr,"phone":phone,"auth":auth} else: return {"code":-1,"msg":"驗簽失敗"} if __name__ == '__main__': uvicorn.run('驗簽:server',port=9000,host='0.0.0.0',debug=True)
當使用postman請求時,如果auth與算法生成的結果不一致,則不會處理這條請求
加密:
背景:實際工作中,有些接口不希望被其他人讀懂入參和出參報文,經常會將參數使用加密后的數據來傳遞入參,比如常用的AES加密,加密和解密使用不同的密鑰
原理:每次請求傳過來的都是一個加密字符串,1.先知道加密的算法是什么 2.每次發請求之前,都把參數加密
#pip install pycrypto from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex import fastapi server = fastapi.FASTAPI() class Prpcrypt(): def __init__(self, key): ''' :param key:security_key,一個16位的隨機字符串,不要讓別人知道 ''' self.key = key.encode() # 加密函數,如果text不是16的倍數【加密文本text必須為16的倍數!】,那就補足為16的倍數 def encrypt(self, text): text = text.encode() cryptor = AES.new(self.key, AES.MODE_CBC, self.key) # 生成一個加密對象 # 這里密鑰key 長度必須為16(AES-128)、24(AES-192)、或32(AES-256)Bytes 長度.目前AES-128足夠用 length = 16 count = len(text) if count % length != 0: # 判斷加密的字符串長度是不是16的倍數 add = length - (count % length) # 如果不是的話,就在前面補多少個/0, 這里的算法是 # 舉例:53/16 商3 余5; 16-5 = 11, 53+11 = 64 ;,64是53上面最小的一個16的倍數 # 53是加密內容的長度,不是16的倍數,通過 16 - (53 % 16 ) 算出需要補多少個/0,加密內容的長度才是16的倍數 else: add = 0 text = text + (b'\0' * add) ciphertext = cryptor.encrypt(text) # 因為AES加密時候得到的字符串不一定是ascii字符集的,輸出到終端或者保存時候可能存在問題 # 所以這里統一把加密后的字符串轉化為16進制字符串,就是b9925b80185497ccbcc3d501604845ee這樣的密文 # b2a_hex這個函數的作用就是把bytes類型的轉成16進制 result = b2a_hex(ciphertext).decode() return result def decrypt(self, text): cryptor = AES.new(self.key, AES.MODE_CBC, self.key) # 生成一個加密對象 plain_text = cryptor.decrypt(a2b_hex(text)) # a2b_hex就是把16進制的轉成bytes類型的 return plain_text.decode() @server.get('/api/test1') def test1('/api/test1'): p = Prpcrypt('1234567890123456') miwen = p.encrypt('{"code":1}') result = p.decrypt(miwen) return {"code":0,"msg":result}