网络数据传输过程,如何保证整个传输过程,该数据没有被篡改过,最常用的就是加入签名,我们可以破译网络加密,可以知道包裹里装着什么,但是如果想要修改内容,就必须知道签名秘钥,很显然python的itsdangerous就是为了这个而设计的。
签名接口
最基本的签名接口:
1 | from itsdangerous import Signer |
2 | |
3 | s = Signer('secret-key') # 加入秘钥 |
4 | s.sign('my name'.encode()) # 对内容签名 |
5 | b'my name.prZ--Y8cQ5HcIvwU-guot-Z3Efg' |
6 | |
7 | # 签名会被加入在字符串的后面,可以使用unsign()方法来获取字符串 |
8 | s = Signer('secret-key') # 必须与签名时的秘钥一致 |
9 | s.unsign(b'my name.prZ--Y8cQ5HcIvwU-guot-Z3Efg') # 对签名进行验证,获取字符串 |
10 | b'my name' |
使用时间戳签名
如果要使用过期的签名,会加入时间戳信息并且签名,在反签名的时候,会验证时间戳有没有过期:
1 | from itsdangerous import TimestampSigner |
2 | |
3 | s = TimestampSigner('secret-key') |
4 | string = s.sign('my name') |
5 | s.unsign(string, max_age=5) # 在反签名的时候时间超过了定义的时间,签名反解报错 |
6 | SignatureExpired: Signature age 15 > 5 seconds |
7 | |
8 | s.unsign(string, max_age=60) |
9 | b'my name' |
序列化
这个模块提供了一个与jason或pickle类似的序列化接口,内部默认通过simplejason实现:
1 | from itsdangerous import Serializer |
2 | |
3 | s = Serializer('secret-key') |
4 | s.dumps('my name') |
5 | '"my name".I8V4bDRuaOhrxycFoBD_bGquWeA' |
6 | |
7 | s.loads('"my name".I8V4bDRuaOhrxycFoBD_bGquWeA') |
8 | 'my name' |
使用时间戳序列化
1 | from itsdangerous import TimedSerializer |
2 | |
3 | s=TimedSerializer('secret-key') |
4 | s.dumps('my name') |
5 | '"my name".DmZ5pw.UmZhVDbFcVDBkVrds3thXG_dAMc' |
6 | |
7 | s.loads('"my name".DmZ5pw.UmZhVDbFcVDBkVrds3thXG_dAMc', max_age=5) |
8 | SignatureExpired: Signature age 20 > 5 seconds |
URL安全序列化
如果能够向只有字符受限的环境中传递可信的字符串的话,将十分有用。
1 | from itsdangerous import URLSafeSerializer |
2 | |
3 | s=URLSafeSerializer('secret-key') |
4 | s.dumps('my name') |
5 | 'Im15IG5hbWUi.tiNo7pfP9cKKiYoGLJrj7yqHmmM' |
6 | |
7 | s.loads('Im15IG5hbWUi.tiNo7pfP9cKKiYoGLJrj7yqHmmM') |
8 | 'my name' |
同样也支持使用时间戳的URL安全序列化
JASON Web签名
JASON WEB签名常常用来jwt使用,用于生成token:
1 | from itsdangerous import JSONWebSignatureSerializer |
2 | |
3 | s = JSONWebSignatureSerializer('SECRET-KEY') |
4 | s.dumps('my_name') |
5 | b'eyJhbGciOiJIUzI1NiJ9.Im15X25hbWUi.qPu33msLT1RNcA8ASFRP8PvwdvSKpmCYVLCeU6ld1M8' |
6 | |
7 | s.loads(b'eyJhbGciOiJIUzI1NiJ9.Im15X25hbWUi.qPu33msLT1RNcA8ASFRP8PvwdvSKpmCYVLCeU6ld1M8') |
8 | 'my_name' |
1 | s = JSONWebSignatureSerializer('SECRET-KEY') |
2 | s.dumps('my_name',header_fields={'v': 1}) |
3 | b'eyJ2IjoxLCJhbGciOiJIUzI1NiJ9.Im15X25hbWUi.h9USP-teoUrCbmE5ubL0o1IRZBkdwk96W0KOmPgR-Sw' |
4 | |
5 | s.loads(b'eyJ2IjoxLCJhbGciOiJIUzI1NiJ9.Im15X25hbWUi.h9USP-teoUrCbmE5ubL0o1IRZBkdwk96W0KOmPgR-Sw', return_header=True) |
6 | ('my_name', {'alg': 'HS256', 'v': 1}) |
使用时间戳的JASON Web签名
1 | from itsdangerous import TimedJSONWebSignatureSerializer |
2 | |
3 | s=TimedJSONWebSignatureSerializer('SECRET_KEY', expires_in=5) # 5秒就过期 |
4 | |
5 | s.dumps('hello') |
6 | b'eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNTQzODU0MywiZXhwIjoxNTM1NDM4NTQ4fQ.ImhlbGxvIg.nO3BkK9EM4IrTqWrNZ1mAl-dx5xUIyf6yBtA293gIWg' |
7 | |
8 | s.loads(b'eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNTQzODU0MywiZXhwIjoxNTM1NDM4NTQ4fQ.ImhlbGxvIg.nO3BkK9EM4IrTqWrNZ1mAl-dx5xUIyf6yBtA293gIWg') |
9 | SignatureExpired: Signature expired |
SALT
所有的类都接受一个salt的参数。密码学中的salt会是一个和被签名的字符串储存在一起的东西,用来防止彩虹表查找。这种salt是公开的。
1 | from itsdangerous import URLSafeSerializer |
2 | |
3 | s = URLSafeSerializer('SECRET-KEY',salt='hello') |
4 | s.dumps('my name', salt='world') |
5 | 'Im15IG5hbWUi.kPvdkG_Grs3Dj5S6nlSZXqJUISY' |
6 | s.loads('Im15IG5hbWUi.kPvdkG_Grs3Dj5S6nlSZXqJUISY') |
7 | BadSignature: Signature b'kPvdkG_Grs3Dj5S6nlSZXqJUISY' does not match |
8 | |
9 | s.loads('Im15IG5hbWUi.kPvdkG_Grs3Dj5S6nlSZXqJUISY', salt='world') |
10 | 'my name' |
只有使用相同盐的序列化器才能成功把值加载出来