A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

Dustin0

初级黑马

  • 黑马币:16

  • 帖子:6

  • 精华:0

© Dustin0 初级黑马   /  2018-9-10 15:11  /  3439 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 Dustin0 于 2020-1-1 23:20 编辑

博客链接地址:http://www.zhuyannan.top/itsdangerous-加密你的数据/
如果你想向不可信的环境发送数据,但又担心数据被别人利用,就可以使用 itsdangerous来加密签名你的数据。
接收者可以破译内容,来看看你的包裹里有什么,但他们没办法修改你的内容,除非他们也有你的密钥。
itsdangerous内部默认使用了HMAC和SHA1来签名,基于 Django 签名模块。它也支持JSON Web 签名 (JWS)。这个库采用BSD协议,由Armin Ronacher编写,而大部分设计与实现的版权归Simon Willison和其他的把这个库变为现实的Django爱好者们。
0.安装
1
pip install itsdangerous
1.签名接口
Signer 类可以用来将一个签名附加到指定的字符串上,这个是最基本的签名接口
1
2
3
4
5
6
In [1]: from itsdangerous import Signer

In [2]: s = Signer('secret_key')

In [3]: s.sign(b'hello')
Out[3]: b'hello.v8Y625GovH2FcEWU_j5w1klqs0I'
可以看出,签名被加到字符串 hello 的尾部,并且以 . 隔开。(注意:这里的 sign() 需要传bytes类型数据,不然会报错)
如果要反签名,使用 unsign() 方法:
1
2
In [4]: s.unsign('hello.v8Y625GovH2FcEWU_j5w1klqs0I') # 这里也可以传bytes数据
Out[4]: b'hello'
如果反签名失败,会得到 BadSignature 的异常。
2.使用时间戳签名
如果想要签名可以过期,可以使用 TimeStampSigner 类,它会加入时间戳信息并签名。
1
2
3
4
5
6
7
8
In [6]: from itsdangerous import TimestampSigner

In [7]: s = TimestampSigner('secret_key')

In [8]: string = s.sign('hello')

In [9]: string
Out[9]: b'hello.DmZg2g.idiRG3HJdMzUNN-di8LXHKiEW5s'
反签名时,可以验证码时间戳是否过期
1
2
3
4
5
6
7
In [10]: s.unsign(string) # 没有输入有效期,是可以直接反签名
Out[10]: b'hello'

In [11]: s.unsign(string,max_age=5)  # 输入有效期 5s
SignatureExpired         Traceback (most recent call last)
.....
SignatureExpired: Signature age 48 > 5 seconds
可以看出在反签名时,我输入了5s的有效期,但是进行反签名时,已经过了48s,所以报错了,提示 Signature age 48 > 5 seconds
3.序列化
对于非字符串的数据,Signer 类处理不了,这个模块也提供了类似 json 的序列化接口 —-> Serializer 类
签名使用 Serializer 对象的 dumps() ,反签名使用 loads()
1
2
3
4
5
6
7
8
9
In [13]: from itsdangerous import Serializer

In [14]: s = Serializer('secret_key')

In [15]: s.dumps({'name':'zhangsan','age':18})
Out[15]: '{"name": "zhangsan", "age": 18}.SQd5BPTqTZQ4vLOEN7PKBYWMsas'

In [16]: s.loads('{"name": "zhangsan", "age": 18}.SQd5BPTqTZQ4vLOEN7PKBYWMsas')
Out[16]: {'name': 'zhangsan', 'age': 18}
4.URL安全序列化
如果要想向不可信的环境传递数据,可以使用URL安全序列化工具
1
2
3
4
5
6
7
8
9
In [23]: from itsdangerous import URLSafeSerializer

In [25]: s = URLSafeSerializer('secret_key')

In [26]: s.dumps([1,2,3])
Out[26]: 'WzEsMiwzXQ.1JvL0-RdbHYdszhKCATOTdQEZl0'

In [27]: s.loads('WzEsMiwzXQ.1JvL0-RdbHYdszhKCATOTdQEZl0')
Out[27]: [1, 2, 3]
同样也有添加时间戳的URL安全序列化类 URLSafeTimedSerializer,就不举例了
5.JSON WEB 签名
它的工作方式与URL安全序列化器差不多
1
2
3
4
5
6
7
8
9
10
In [29]: from itsdangerous import JSONWebSignatureSerializer

In [30]: s = JSONWebSignatureSerializer('secret_key')

In [31]: s.dumps({'name':'mike'})
Out[31]: b'eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibWlrZSJ9.A9eujaivW63mvCSmz_6KVT6sDtLneBe3U62wCoSellY'

In [32]: s.loads('eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibWlrZSJ9.A9eujaiv
    ...: W63mvCSmz_6KVT6sDtLneBe3U62wCoSellY')
Out[32]: {'name': 'mike'}
但是会根据当前 JSON Web签名(JWS) 草案(10) [draft-ietf-jose-json-web-signature] 来生成 header。
签名时可以传入header_fields 参数,反签名传入return_header=True 参数来得到 header
1
2
3
4
5
6
In [34]: s.dumps({'name':'mike'},header_fields={'myheader':123})
Out[34]: b'eyJteWhlYWRlciI6MTIzLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibWlrZSJ9.mE-UAcsVsqisJj6EIOF1ocahGdRz5cbZyyySF39OREQ'

In [35]: s.loads('eyJteWhlYWRlciI6MTIzLCJhbGciOiJIUzI1NiJ9.eyJuYW1lI
    ...: joibWlrZSJ9.mE-UAcsVsqisJj6EIOF1ocahGdRz5cbZyyySF39OREQ',return_header=True)
Out[35]: ({'name': 'mike'}, {'myheader': 123, 'alg': 'HS256'})
加载回来的header里还包含当前使用的算法 {‘alg’: ‘HS256’},itsdangerous 目前只提供HMAC SHA的派生算法以及不使用算法,不支持基于ECC的算法。
6.TimedJSONWebSignatureSerializer
带有时间戳的JSON WEB 签名
1
2
3
4
5
6
7
8
9
10
11
12
13
In [42]: from itsdangerous import TimedJSONWebSignatureSerializer

In [43]: s = TimedJSONWebSignatureSerializer('secret_key',10)  # 设置有效期为 10s

In [44]: s.dumps({'id':1})
Out[44]: b'eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNTQzNTg3NSwiZXhwIjoxNTM1NDM1ODg1fQ.eyJpZCI6MX0.vZ5fDRR1-zBJk2nOH7kpdQIxvEv8dru0C3o_wuagIec'

In [45]: s.loads('eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNTQzNTg3NSwiZXhwIj
    ...: oxNTM1NDM1ODg1fQ.eyJpZCI6MX0.vZ5fDRR1-zBJk2nOH7kpdQIxvEv8dr
    ...: u0C3o_wuagIec')
                  Traceback (most recent call last)
                 .....
                 SignatureExpired: Signature expired
可以看出,反签名时抛出 SignatureExpired 签名过期的错误,原因是因为我设置了有效期10s,但是我执行反签名时,时间已经过了 10s 的有效期。
7.加盐加密
itsdangerous 中所有的类都接收一个盐的参数,密码学中的盐是一个和被签名的字符串存储在一起的东西,作用是防止彩虹表查找。这种盐是可以公开的。你可以将它视为一个命名空间,泄露也没事,只要密钥没泄露,攻击者就没办法破解。
举个简单的例子来演示:
假设你想签名链接,一个邮箱激活链接,一个邮箱升级VIP的链接,签名都是 user ID,那么在激活和升级时就可以复用这个可变的部分,但是可以在签名的地方加上更多信息,使用不同的盐来说明你的意图。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In [36]: s = URLSafeSerializer('scret_key',salt='verify_salt')  # 激活使用的盐
                                                                 
In [37]: s.dumps(10)   # 假设用户的 id=10                                          
Out[37]: 'MTA.jz5Oj-RsTztx1o0KQhhjdEL2z9E'                       
                                                                 
In [38]: s_vip = URLSafeSerializer('secret_key',salt='vip_salt') # 升级vip使用的盐
                                                                 
In [39]: s_vip.dumps(10)                                         
Out[39]: 'MTA.j_qvVU-kNlTimdlgMty0qcy_618'                       

# 反签名时,使用 salt=vip_salt 的对象去加载 salt='verify_salt' 对象,就会报签名错误
In [40]: s_vip.loads(s.dumps(10))  
    Traceback (most recent call last)
        .....
    BadSignature: Signature b'jz5Oj-RsTztx1o0KQhhjdEL2z9E' does not match

# 使用相同盐的序列化器才能成功反签名
In [41]: s_vip.loads(s_vip.dumps(10))
Out[41]: 10


3 个回复

正序浏览
66666
回复 使用道具 举报
回复 使用道具 举报
、加油加油
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马