Flask-Security令牌是如何创建的?

时间:2016-12-27 09:20:14

标签: python flask flask-security

我正在尝试了解flask-security令牌创建的工作原理。我的flask应用程序配置中有一个密钥,但我们的代码是开源的,并且在python中,所以它不是很秘密,真的。

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

    serializer = current_app.extensions['security'].remember_token_serializer

然后我可以serializer.loads(token)并收到用户名和哈希密码。

所以我的问题是这样:什么阻止恶意用户收听我的流量,具有密钥,做同样的事情 - 获得flask-security令牌序列化程序,并反序列化我的令牌? flask在创建令牌时是否使用了其他一些盐?但是,如果要重新启动服务,它将如何解密令牌?

1 个答案:

答案 0 :(得分:3)

我不完全确定实施细节以及如何生成令牌(但我非常确定烧瓶安全性使用itsdangerous)。

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

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

是的,任何人都可以查看内部并查看令牌中包含的内容,重点是没有密钥没有人可以篡改数据,如果攻击者生成自己的令牌,他必须使用{{ 1}}否则该标记将被烧瓶安全性拒绝,因为它无效。

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

我们假设在您的应用中,您只会通过检查令牌中的参数secret key是否设置为is_admin来授予用户管理员权限。

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

'true'

在某种程度上,攻击者拦截令牌并且足够聪明,他知道令牌是base64编码的字符串,因此可以很容易地将它们解码回原始形式。 Python甚至在标准库中都有一个模块,所以他不必为自己压力。

from itsdangerous import URLSafeSerializer

>>> s = URLSafeSerializer('secret key')
>>> s.dumps({'username': 'john', 'is_admin': 'false'})
'eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6ImZhbHNlIn0.k45WPrVOG1Nrags0bwpVUbS7Vcw'

就像他能够解码我们的令牌并查看其中的内容(这就是为什么密码被哈希以获得额外的安全性)

由于他知道我们期望的参数,因此可以自然地猜测import base64 >>> base64.b64decode('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6ImZhbHNlIn0===') b'{"username":"john","is_admin":"false"}' 设置为is_admin的任何用户都可以访问普通用户不会访问的内容,然后他会这样做继续生成自己的令牌。

由于他没有我们的服务器秘密,他只是使用随机秘密

true

好,然后他将令牌发送到我们的服务器。

当我们尝试使用我们的Serializer(已配置为使用我们的服务器密钥)解码令牌时,我们会收到错误消息。并且攻击者无法进入,因为他使用了错误的秘密来签署他的令牌。

>>> 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
>>>

即使您尝试将权利令牌中的签名附加到错误的数据上,它也无法生效,您仍然会收到错误

# We can always load the correct token back
 s.loads('eyJ1c2VybmFtZSI6ImpvaG4iLCJpc19hZG1pbiI6ImZhbHNlIn0.k45WPrVOG1Nrags0bwpVUbS7Vcw')
{'username': 'john', 'is_admin': 'false'}

免责声明:这可能不是烧瓶安全的确切实现,但我的回答应该让您了解幕后发生的事情。您可能还想阅读JSON web tokens

并且不要将您的秘密存储在配置文件中,将其存储在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 (不能成为源代码管理的一部分)中,或者将其设置为环境变量并导出/设置生产环境中的变量。

结帐dotenv