使用场景:
- 在取消订阅时,可以在URL里序列化并且签名一个用户的ID或在任何的激活账户的链接或类似的情形下使用。这种情况下不需要生成一个一次性的token并把它们存到数据库中。
- 被签名的对象可以被存入cookie中或其他不可信来源,这意味着不需要在服务端保存session,这样可以降低数据库读取的次数。
- 通常签名后的信息可以安全地往返与服务端与客户端之间,这个特性可以用于将服务端的状态传递到客户端再传递回来。
签名接口:
最基本的接口是签名接口。Signer
类可以用来将一个签名附加到指定的字符串上
注:sign()方法需要传bytes类型数据,不然会报错
# 发送方和接收方拥有相同的密钥--"secret-key",发送方使用密钥对发送内容进行签名,接收方使用相同的密钥对接收到的内容进行验证,看是否是发送方发送的内容 from itsdangerous import Signer s = Signer('secret-key') # 参数传自己的密钥 s.sign(b'1234566322345663') #获取签名,得到的结果是签名加在传入的字符串尾部,以.分隔 # b'1234566322345663.DWnk3y4kwfTAiTJ1kNZ1mNSabOU' # 验证字符串,使用unsign()方法: s.unsign('1234566322345663.DWnk3y4kwfTAiTJ1kNZ1mNSabOU')
# 如果被签名的是一个unicode字符串,那么它将隐式地被转换成utf-8。然而,在反签名时,你没法知道它原来是unicode还是字节串。 # 如果反签名验证失败了,会主动抛出异常 '''itsdangerous.exc.BadSignature: Signature b'DWnk3y4kwfTAiTJ1kNZ1mNSabOUsd' does not match'''
使用时间戳签名:
如果想要可以过期的签名,可以使用TimestampSigner
类,它会加入时间戳信息并签名。在反签名时,可以验证时间戳有没有过期
from itsdangerous import TimestampSigner s1 = TimestampSigner('secret-key') # string = s1.sign('foo') # b'foo.XSmkVg.A6ZSwzOnVlVaNCkk12Fqo4gFRQk' # 得到签名结果后,将上面签名的代码先注释掉,然后再反签名 s1.unsign('foo.XSmkVg.A6ZSwzOnVlVaNCkk12Fqo4gFRQk', max_age=5) # 这里设置的5s过期,那么只要反签名的时间超过5s都是过期,下面是异常信息 '''itsdangerous.exc.SignatureExpired: Signature age 34 > 5 seconds'''
序列化:
# 因为字符串难以处理,本模块也提供了一个与json或pickle类似的序列化接口。(它内部默认使用simplejson,但是可以通过子类进行修改) from itsdangerous import Serializer
# 签名 s2 = Serializer('secret-key')
s2.dumps([1, 2, 3, 4]) # [1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo # 反签名,加载数据 s2.loads('[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo')
带时间戳的序列化:
from itsdangerous import TimedSerializer
# 签名 s=TimedSerializer('secret-key') s.dumps([1,2,3,4]) # '[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc' s.loads('[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc') # [1, 2, 3, 4] s.loads('[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc',max_age=10) # [1, 2, 3, 4]
URL安全序列化:
如果能够向只有字符受限的环境中传递可信的字符串的话,将十分有用。itsdangerous也提供了一个URL安全序列化工具
from itsdangerous import URLSafeSerializer # 签名 s = URLSafeSerializer('secret-key') s.dumps([1, 2, 3, 4]) # 'WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo' # 反签名 s.loads('WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo') # [1, 2, 3, 4]
JSON Web 签名:
json web签名工作方式与原有的URL安全序列化差不多,但是会根据当前JSON Web签名
from itsdangerous import JSONWebSignatureSerializer # 签名 s = JSONWebSignatureSerializer('secret-key') s.dumps({'x': 42}) # 'eyJhbGciOiJIUzI1NiJ9.eyJ4Ijo0Mn0.ZdTn1YyGz9Yx5B5wNpWRL221G1WpVE5fPCPKNuc6UAo' s.dumps(0, header_fields={'v': 1}) # 'eyJhbGciOiJIUzI1NiIsInYiOjF9.MA.wT-RZI9YU06R919VBdAfTLn82_iIQD70J_j-3F4z_aM' # 反签名 s.loads('eyJhbGciOiJIUzI1NiIsInYiOjF9.MA.wT-RZI9YU06R919VBdAfTLn82_iIQD70J_j-3F4z_aM', return_header=True) # (0, {u'alg': u'HS256', u'v': 1})
根据当前JSON Web签名(JWS)草案(10)[draft-ietf-jose-json-web-signature] 来生成 header。签名时可以传入header_fields 参数,反签名传入return_header=True参数来得到header
带有时间戳的JSON WEB 签名:
from itsdangerous import TimedJSONWebSignatureSerializer s = TimedJSONWebSignatureSerializer('secret_key',10) # 设置有效期为10s # 签名 s.dumps({'id':1}) # 反签名 s.loads('xxxxxxxxxxxx') # 如果超过设置的有效期则反签名时抛出SignatureExpired签名过期的错误
加盐加密:
itsdangerous 中所有的类都接收一个盐的参数salt,密码学中的盐是一个和被签名的字符串存储在一起的东西,作用是防止彩虹表查找。这种盐是可以公开的。你可以将它视为一个命名空间,泄露也没事,只要密钥没泄露,攻击者就没办法破解。
使用举例:在对同一个用户的激活账户和升级vip时加入不同的盐值,即可得到不同的签名,且使用相同盐的序列化器才能成功反签名。