Jusene's Blog

It's dangerous, so better sign this

字数统计: 697阅读时长: 3 min
2018/08/27 Share

网络数据传输过程,如何保证整个传输过程,该数据没有被篡改过,最常用的就是加入签名,我们可以破译网络加密,可以知道包裹里装着什么,但是如果想要修改内容,就必须知道签名秘钥,很显然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'

只有使用相同盐的序列化器才能成功把值加载出来

CATALOG
  1. 1. 签名接口
  2. 2. 使用时间戳签名
  3. 3. 序列化
  4. 4. 使用时间戳序列化
  5. 5. URL安全序列化
  6. 6. JASON Web签名
  7. 7. 使用时间戳的JASON Web签名
  8. 8. SALT