如果未设置app.secret_key
,Flask将不允许您设置或访问会话字典。
这就是主题flask user guide has to say的所有内容。
我是网络开发的新手,我不知道为什么/为什么安全的东西有效。我想了解Flask在幕后做的事情。
secret_key
属性? secret_key
属性?答案 0 :(得分:77)
任何需要加密的东西(为了安全防止攻击者的篡改)都需要设置密钥。对于只是 Flask本身,“任何”都是Session
对象,但其他扩展可以使用相同的秘密。
secret_key
只是为SECRET_KEY
配置键设置的值,或者您可以直接设置它。
Sessions section in the Quickstart对你应该设置什么样的服务器端秘密有一个很好的,明智的建议。
加密依赖于秘密;如果您没有为加密设置服务器端密码,那么每个人都可以破解加密;它就像是你电脑的密码。秘密加上数据到符号用于创建签名字符串,使用cryptographic hashing algorithm创建难以重建的值;只有当您拥有完全相同的秘密和时,原始数据才能重新创建此值,让Flask检测是否未经许可更改了任何内容。由于Flask发送给客户端的数据从不包含秘密,因此客户端无法篡改会话数据并希望生成新的有效签名。
Flask使用itsdangerous
library来完成所有艰苦工作;会话使用itsdangerous.URLSafeTimedSerializer
class和自定义的JSON序列化程序。
答案 1 :(得分:42)
以下答案主要涉及签名Cookie ,会话概念的实现(在Web应用程序中使用)。 Flask提供普通(未签名)Cookie(通过request.cookies
和response.set_cookie()
)和签名Cookie(通过flask.session
)。答案分为两部分,第一部分描述了如何生成签名Cookie,第二部分以质量保证的形式呈现,解决了该方案的不同方面。用于示例的语法是Python3,但这些概念也适用于以前的版本。
SECRET_KEY
(或如何创建签名Cookie)?签署cookie是防止cookie篡改的预防措施。在签署cookie的过程中,SECRET_KEY
的使用方式类似于" salt"将用于在散列密码之前混淆密码。这是一个(疯狂)简化的概念描述。示例中的代码是说明性的。许多步骤已被省略,并非所有功能实际存在。这里的目标是提供对一般概念的理解,实际实现将涉及更多。此外,请记住,Flask在后台为您完成了大部分工作。因此,除了为您的Cookie设置值(通过会话API)并提供SECRET_KEY
之外,不仅不建议您自己重新实现,而且没有必要这样做:< / p>
(1)首先建立SECRET_KEY
。应该只知道应用程序,并且应该在应用程序的生命周期中保持相对稳定,包括通过应用程序重新启动。
# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')
(2)创建一个cookie
>>> cookie = make_cookie(
... name='_profile',
... content='uid=382|membership=regular',
... ...
... expires='July 1 2030...'
... )
>>> print(cookie)
name: _profile
content: uid=382|membership=regular...
...
...
expires: July 1 2030, 1:20:40 AM UTC
(3)创建签名,将SECRET_KEY
附加(或前置)到cookie字节字符串,然后从该组合生成散列。
# encode and salt the cookie, then hash the result
>>> cookie_bytes = str(cookie).encode('utf8')
>>> signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
>>> print(signature)
7ae0e9e033b5fa53aa....
(4)现在将签名粘贴在原始cookie的content
字段的一端。
# include signature as part of the cookie
>>> cookie.content = cookie.content + '|' + signature
>>> print(cookie)
name: _profile
content: uid=382|membership=regular|7ae0e9... <--- signature
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
以及那些发送给客户的内容。
# add cookie to response
>>> response.set_cookie(cookie)
# send to browser -->
(5)当浏览器将此cookie返回给服务器时,从cookie的content
字段中删除签名以取回原始cookie。
# Upon receiving the cookie from browser
>>> cookie = request.get_cookie()
# pop the signature out of the cookie
>>> (cookie.content, popped_signature) = cookie.content.rsplit('|', 1)
(6)使用原始cookie和应用程序的SECRET_KEY
,使用与步骤3中相同的方法重新计算签名。
# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
(7)将计算结果与先前从刚收到的cookie中弹出的签名进行比较。如果它们匹配,我们就知道cookie没有被搞砸了。但即使只是在cookie中添加了一个空格,签名也不会匹配。
# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature
(8)如果他们不匹配,那么您可以回复任意数量的操作,记录事件,丢弃cookie,发布新的,重定向到登录页面等。
>>> if not good_cookie:
... security_log(cookie)
上面生成的签名类型需要密钥以确保某些内容的完整性在加密中调用消息验证代码或 MAC 。
我之前指出,上面的例子过于简单化了这个概念,并且实现自己的签名并不是一个好主意。这是因为用于在Flask中签名cookie的算法称为HMAC,并且比上述简单的步骤更复杂。一般的想法是相同的,但由于超出本讨论范围的原因,一系列的计算有点复杂。 如果您仍然对制作DIY感兴趣,通常情况下,Python有一些模块可以帮助您入门:)这里是一个起点:
import hmac
import hashlib
def create_signature(secret_key, msg, digestmod=None):
if digestmod is None:
digestmod = hashlib.sha1
mac = hmac.new(secret_key, msg=msg, digestmod=digestmod)
return mac.digest()
SECRET_KEY
:)&#34;签名&#34;在这种情况下?
这是一种确保某些内容未经授权的人或实体以外的任何人修改的方法。
最简单的签名形式之一是&#34; checksum&#34;,它只是验证两个数据是否相同。例如,从源代码安装软件时,首先要确认您的源代码副本与作者相同,这一点非常重要。执行此操作的常用方法是通过加密哈希函数运行源,并将输出与项目主页上发布的校验和进行比较。
例如,假设您要从Web镜像下载gzip压缩文件中的项目源代码。在项目网页上发布的SHA1校验和是&#39; eb84e8da7ca23e9f83 ......&#39;
# so you get the code from the mirror
download https://mirror.example-codedump.com/source_code.tar.gz
# you calculate the hash as instructed
sha1(source_code.tar.gz)
> eb84e8da7c....
两个哈希都是相同的,你知道你有一个相同的副本。
什么是cookie?
关于cookie的广泛讨论超出了本问题的范围。我在这里提供了一个概述,因为最小的理解对于更好地理解SECRET_KEY
如何以及为何有用是有用的。我强烈建议您跟进一些有关HTTP Cookie的个人阅读材料。
Web应用程序的一种常见做法是将客户端(Web浏览器)用作轻量级缓存。 Cookie是这种做法的一种实现方式。 Cookie通常是服务器通过其标头添加到http响应的一些数据。它由浏览器保存,随后在发出请求时也通过http标头将其发送回服务器。 Cookie中包含的数据可用于模拟名为 statefulness 的内容,即服务器与客户端保持持续连接的错觉。只有在这种情况下,您只需要处理客户端请求后,就可以获得应用程序状态的快照,而不是使用连线来保持连接“活动”。这些快照在客户端和服务器之间来回传递。在接收到请求时,服务器首先读取cookie的内容以重新建立其与客户端的对话的上下文。然后,它在该上下文中处理请求,并在将响应返回给客户端之前更新cookie。因此保持了正在进行的会议的错觉。
Cookie看起来像什么?
典型的cookie看起来像这样:
name: _profile
content: uid=382|status=genie
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
从任何现代浏览器中浏览Cookie都是微不足道的。例如,在Firefox上,转到首选项&gt;隐私&gt;历史&gt;删除单个cookie 。
content
字段与应用程序最相关。其他字段主要包含元指令以指定各种影响范围。
为什么要使用cookies?
简短的回答是表现。使用cookie,最大限度地减少了在各种数据存储(内存缓存,文件,数据库等)中查找内容的需要,从而加快了服务器应用程序的速度。请记住,cookie越大,网络上的有效负载越重,因此您在服务器上的数据库查找中可能会节省您在网络上丢失的内容。仔细考虑您的cookie中包含哪些内容。
为什么需要签署cookie?
Cookie用于保存各种信息,其中一些信息可能非常敏感。它们本质上也不安全,并要求对双方,客户和服务器采取一些辅助预防措施以任何方式保证安全。签署cookie专门解决了他们在试图欺骗服务器应用程序时可能会遇到的问题。还有其他措施可以缓解其他类型的漏洞,我建议您阅读更多有关cookie的信息。
如何篡改cookie?
Cookie以文本形式驻留在客户端上,可以毫不费力地进行编辑。您的服务器应用程序收到的cookie可能由于多种原因而被修改,其中一些可能不是无辜的。想象一下,一个Web应用程序可以在cookie上保留有关其用户的权限信息,并根据该信息授予权限。如果cookie没有修补,那么任何人都可以修改他们的状态,以提升他们的状态#role; role = visitor&#34; to&#34; role = admin&#34;并且应用程序将不再是明智的。
为什么签署Cookie需要
SECRET_KEY
?
验证cookie与按照前面描述的方式验证源代码有点不同。在源代码的情况下,原始作者是参考指纹(校验和)的受托人和所有者,其将被公开。您不信任的是源代码,但您信任公共签名。因此,要验证您的源副本,您只需要将计算出的哈希值与公共哈希值匹配。
如果是Cookie,应用程序不会跟踪签名,它会跟踪其SECRET_KEY
。 SECRET_KEY
是参考指纹。 Cookies旅行时带有他们声称合法的签名。这里的合法性意味着签名是由cookie的所有者(即应用程序)发出的,在这种情况下,它声称您不信任,并且您需要检查签名的有效性。要做到这一点,您需要在签名中包含一个仅为您所知的元素,即SECRET_KEY
。有人可能会改变一个cookie,但由于他们没有秘密成分来正确计算有效签名,他们无法欺骗它。如前所述,这种类型的指纹识别在校验和之上也提供了一个密钥,称为消息认证码。
Sessions怎么样?
经典实施中的会话是仅在content
字段session_id
中带有ID的Cookie。会话的目的与签名的cookie完全相同,即防止cookie被篡改。然而,古典会议有不同的方法。在接收到会话cookie时,服务器使用该ID在其自己的本地存储器中查找会话数据,该存储器可以是数据库,文件,或者有时是存储器中的高速缓存。会话cookie通常设置为在浏览器关闭时到期。由于本地存储查找步骤,会话的这种实现通常会导致性能损失。签名cookie正在成为首选的替代方案,以及Flask会话的实施方式。换句话说,Flask会话是签名的cookie,并且要在Flask中使用签名的cookie,只需使用其Session
API。
为什么不加密cookie?
有时,在签名之前,可以对cookie的内容进行加密。如果它们被认为太敏感而无法从浏览器中看到(加密隐藏内容),则会执行此操作。然而,只需签署cookie即可满足不同的需求,即需要在浏览器上保持一定程度的可见性和cookie可用性,同时防止他们被干扰。
如果我更改
会怎样?SECRET_KEY
?
更改SECRET_KEY
您无效使用上一个密钥签名的所有 Cookie。当应用程序收到带有使用之前SECRET_KEY
签名的Cookie的请求时,它会尝试使用新的SECRET_KEY
计算签名,并且两个签名都不匹配,此Cookie和它的所有数据都将被拒绝,就像浏览器第一次连接到服务器一样。用户将被注销,他们的旧cookie被遗忘在内部。请注意,这与处理过期cookie的方式不同。如果签名过期,过期的cookie可能会延长其租约。无效的签名只暗示一个普通的无效cookie。
因此,除非您要使所有已签名的Cookie无效,否则请尝试将SECRET_KEY
保持相同的状态。
什么是好
SECRET_KEY
?
秘密密钥应该难以猜测。 Sessions上的文档有一个很好的随机密钥生成方法:
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
您复制密钥并将其粘贴到配置文件中,作为SECRET_KEY
的值。
如果不使用随机生成的密钥,您可以使用复杂的单词,数字和符号,也可以排列在只有您自己知道的句子中,以字节形式编码。
不直接使用每次调用时生成不同密钥的函数设置SECRET_KEY
。例如,不要这样做:
# this is not good
SECRET_KEY = random_key_generator()
每次重新启动应用程序时,都会给它一个新密钥,从而使之前的代码无效。
而是打开一个交互式python shell并调用该函数生成密钥,然后将其复制并粘贴到配置中。