Python 如何创建Flask安全令牌?

Python 如何创建Flask安全令牌?,python,flask,flask-security,Python,Flask,Flask Security,我正在试图了解flask安全性令牌创建是如何工作的。我在我的flask应用程序配置中有一个密钥,但是我们的代码是开源的,并且是python的,所以它实际上不是很机密 我可以在代码中访问创建令牌的序列化程序: serializer = current_app.extensions['security'].remember_token_serializer 然后我可以执行serializer.load(token)并接收用户名和哈希密码 因此,我的问题是:如何防止恶意用户监听我的流量(具有

我正在试图了解
flask安全性
令牌创建是如何工作的。我在我的
flask
应用程序配置中有一个密钥,但是我们的代码是开源的,并且是python的,所以它实际上不是很机密

我可以在代码中访问创建令牌的序列化程序:

    serializer = current_app.extensions['security'].remember_token_serializer
然后我可以执行
serializer.load(token)
并接收用户名和哈希密码


因此,我的问题是:如何防止恶意用户监听我的流量(具有密钥)执行相同的操作—获取
flask security
令牌序列化程序,并反序列化我的令牌?在创建代币时,
flask
是否使用其他盐?但是,如果重新启动服务,它将如何破译令牌?

我不完全确定实现细节以及令牌是如何生成的(但我非常确定flask security使用的是什么)

令牌的主要用途不是存储您不希望任何人看到的秘密,因为令牌可以很容易地被任何人解码和查看(这就是采取额外步骤存储无法解密的密码哈希的原因)

令牌用于将数据从一个源(客户端)发送到另一个源(服务器),并确保数据不会被任何人修改或更改

是的,任何人都可以查看令牌中包含的内容,关键是没有密钥,任何人都不能篡改数据,如果攻击者生成自己的令牌,他必须使用
密钥
,否则flask security将拒绝该令牌,因为它无效

下面是一个快速演示,演示了我使用它的意思(Flask本身使用这个库进行会话)

假设在应用程序中,您仅通过检查用户是否在令牌中将参数
设置为
'true'
来授予管理员访问权限

非管理员用户John进行身份验证并将其令牌发送给他

from itsdangerous import URLSafeSerializer

>>> s = URLSafeSerializer('secret key')
>>> s.dumps({'username': 'john', 'is_admin': 'false'})
'eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6ImZhbHNlIn0.k45WPrVOG1Nrags0bwpVUbS7Vcw'
不知何故,攻击者截获了令牌,并且足够聪明,他知道令牌是base64编码字符串,因此可以轻松地将其解码回原始形式。Python甚至在标准库中有一个用于此的模块,因此他不必强调自己

import base64
>>> base64.b64decode('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6ImZhbHNlIn0===')
b'{"username":"john","is_admin":"false"}'
就像那样,他能够解码我们的令牌,并看到里面有什么(这就是为什么密码被哈希为额外的安全性)

由于他知道我们期望的参数,因此很自然地会猜测,任何将
设置为
true
的用户都有更多的权限访问正常用户不会访问的内容,然后他继续生成自己的令牌

因为他没有我们的服务器机密,他只是使用了一个随机的机密

>>> t = URLSafeSerializer('fake key')
>>> t.dumps({'username': 'john', 'is_admin': 'true'})
'eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6InRydWUifQ.fPUeGmfSaQWCysy5WWTmmMeuo6c'
很好,然后他将令牌发送到我们的服务器

当我们尝试用序列化程序(已配置为使用服务器密钥)解码令牌时,我们将得到一个错误。攻击者无法进入,因为他使用了错误的秘密来签署他的令牌

>>> s.loads('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6InRydWUifQ.fPUeGmfSaQWCysy5WWTmmMeuo6c')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 582, in loads
    return self.load_payload(self.make_signer(salt).unsign(s))
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 374, in unsign
    payload=value)
itsdangerous.BadSignature: Signature b'fPUeGmfSaQWCysy5WWTmmMeuo6c' does not match
>>>
即使您尝试将正确令牌中的签名附加到错误数据,它也将无效,并且您仍然会得到一个错误

s.loads('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6InRydWUifQ.k45WPrVOG1Nrags0bwpVUbS7Vcw')

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 582, in loads
    return self.load_payload(self.make_signer(salt).unsign(s))
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 374, in unsign
    payload=value)
itsdangerous.BadSignature: Signature b'k45WPrVOG1Nrags0bwpVUbS7Vcw' does not match
s.loads('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6InRydWUifQ.K45WPRVOG1NRAGS0BWPUBS7VCW')
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/home/danidee/venv/lib/python3.5/site packages/itsdiregious.py”,第582行,装入
返回self.load\u有效负载(self.make\u签名者(salt.unsign))
文件“/home/danidee/venv/lib/python3.5/site-packages/itsDanger.py”,第374行,未签名
有效载荷=值)
ItsDanger.BadSignature:签名b'K45WPRVOG1NRAGS0BWPUBS7VCW'不匹配
免责声明:这可能不是flask security中的确切实现,但我的回答应该能让您了解幕后发生了什么。你可能还想读一读

不要将机密存储在配置文件中,而是将其存储在
.env
(不属于源代码管理的一部分)中,或者将其作为环境变量并在生产环境中导出/设置该变量


结帐

谢谢您的精彩回答!这使问题更加清楚。我现在明白了,我们需要将密钥移到配置文件或env var中。
s.loads('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6InRydWUifQ.k45WPrVOG1Nrags0bwpVUbS7Vcw')

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 582, in loads
    return self.load_payload(self.make_signer(salt).unsign(s))
  File "/home/danidee/venv/lib/python3.5/site-packages/itsdangerous.py", line 374, in unsign
    payload=value)
itsdangerous.BadSignature: Signature b'k45WPrVOG1Nrags0bwpVUbS7Vcw' does not match