Python 揭秘 Flask app.secret_key
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22463939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
demystify Flask app.secret_key
提问by MYV
If app.secret_keyisn't set, Flask will not allow you to set or access the session dictionary.
如果app.secret_key未设置,Flask 将不允许您设置或访问会话字典。
This is all that the flask user guide has to sayon the subject.
这就是Flask 用户指南对这个主题所说的全部内容。
I am very new to web development and I have no idea how/why any security stuff works. I would like to understand what Flask is doing under the hood.
我对 Web 开发很陌生,我不知道任何安全性的东西是如何/为什么工作的。我想了解 Flask 在幕后做了什么。
- Why does Flask force us to set this
secret_keyproperty? - How does Flask use the
secret_keyproperty?
- 为什么 Flask 强制我们设置这个
secret_key属性? - Flask 如何使用该
secret_key属性?
采纳答案by Martijn Pieters
Anything that requires encryption (for safe-keeping against tampering by attackers) requires the secret key to be set. For justFlask itself, that 'anything' is the Sessionobject, but other extensions can make use of the same secret.
任何需要加密(为了防止被攻击者篡改)的东西都需要设置密钥。对于刚刚瓶本身,即“什么”是Session对象,但其他的扩展可以使用相同的秘密的。
secret_keyis merely the value set for the SECRET_KEYconfiguration key, or you can set it directly.
secret_key只是为SECRET_KEY配置键设置的值,或者您可以直接设置它。
The Sessions section in the Quickstarthas good, sane advice on what kind of server-side secret you should set.
Quickstart 中的Sessions 部分对您应该设置什么样的服务器端机密有很好的、合理的建议。
Encryption relies on secrets; if you didn't set a server-side secret for the encryption to use, everyone would be able to break your encryption; it's like the password to your computer. The secret plus the data-to-sign are used to create a signature string, a hard-to-recreate value using a cryptographic hashing algorithm; only if you have the exact same secret andthe original data can you recreate this value, letting Flask detect if anything has been altered without permission. Since the secret is never included with data Flask sends to the client, a client cannot tamper with session data and hope to produce a new, valid signature.
加密依赖于秘密;如果您没有为要使用的加密设置服务器端机密,那么每个人都可以破解您的加密;它就像你电脑的密码。秘密加上要签名的数据用于创建签名字符串,这是一个使用加密散列算法难以重新创建的值;只有当你拥有完全相同的秘密和原始数据时,你才能重新创建这个值,让 Flask 检测是否有任何未经许可的更改。由于 Flask 发送给客户端的数据中永远不会包含机密,因此客户端无法篡改会话数据并希望生成新的有效签名。
Flask uses the itsdangerouslibraryto do all the hard work; sessions use the itsdangerous.URLSafeTimedSerializerclasswith a customized JSON serializer.
Flask 使用itsdangerous库来完成所有繁重的工作;会话使用带有自定义 JSON 序列化程序的itsdangerous.URLSafeTimedSerializer类。
回答by Michael Ekoka
The answer below pertains primarily to Signed Cookies, an implementation of the concept of sessions(as used in web applications). Flask offers both, normal (unsigned) cookies (via request.cookiesand response.set_cookie()) and signed cookies (via flask.session). The answer has two parts, the first describes how a Signed Cookie is generated, and the second is presented in the form of a QA that addresses different aspects of the scheme. The syntax used for the examples is Python3, but the concepts apply also to previous versions.
下面的答案主要与Signed Cookies 相关,它是会话概念的实现(在 Web 应用程序中使用)。Flask 提供普通(未签名)cookie(viarequest.cookies和response.set_cookie())和签名 cookie(via flask.session)。答案有两个部分,第一个部分描述了签名 Cookie 的生成方式,第二个部分以解决方案不同方面的 QA 的形式呈现。示例使用的语法是 Python3,但这些概念也适用于以前的版本。
What is SECRET_KEY(or how to create a Signed Cookie)?
什么是SECRET_KEY(或如何创建签名 Cookie)?
Signing cookies is a preventive measure against cookie tampering. During the process of signing a cookie, the SECRET_KEYis used in a way similar to how a "salt" would be used to muddle a password before hashing it. Here's a (wildly) simplified description of the concept. The code in the examples is meant to be illustrative. Many of the steps have been omitted and not all of the functions actually exist. The goal here is to provide an understanding of the general idea, actual implementations will be a bit more involved. Also, keep in mind that Flask does most of this for you in the background. So, besides setting values to your cookie (via the session API) and providing a SECRET_KEY, it's not only ill-advised to reimplement this yourself, but there's no need to do so:
签署 cookie 是一种防止 cookie 篡改的预防措施。在对 cookie 进行签名的过程中,SECRET_KEY它的使用方式类似于在散列密码之前使用“盐”来混淆密码的方式。这是对该概念的(疯狂)简化描述。示例中的代码旨在说明。许多步骤已被省略,并非所有功能都实际存在。这里的目标是提供对一般思想的理解,实际实现将涉及更多。另外,请记住,Flask 在后台为您完成了大部分工作。因此,除了值设为您的Cookie(通过会话API)和提供SECRET_KEY,它不仅是不明智的这个重新实现自己,但没有这样做的必要:
A poor man's cookie signature
一个穷人的饼干签名
Before sending a Response to the browser:
在向浏览器发送响应之前:
( 1 ) First a SECRET_KEYis established. It should only be known to the application and should be kept relatively constant during the application's life cycle, including through application restarts.
(1)首先aSECRET_KEY成立。它应该只为应用程序所知,并且应该在应用程序的生命周期中保持相对恒定,包括通过应用程序重新启动。
# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')
( 2 ) create a cookie
(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 ) to create a signature, append (or prepend) the SECRET_KEYto the cookie byte string, then generate a hash from that combination.
( 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 ) Now affix the signature at one end of the contentfield of the original cookie.
(4) 现在content在原始cookie的字段的一端加上签名。
# 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
and that's what's sent to the client.
这就是发送给客户端的内容。
# add cookie to response
>>> response.set_cookie(cookie)
# send to browser -->
Upon receiving the cookie from the browser:
从浏览器接收 cookie 后:
( 5 ) When the browser returns this cookie back to the server, strip the signature from the cookie's contentfield to get back the original cookie.
(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 ) Use the original cookie with the application's SECRET_KEYto recalculate the signature using the same method as in step 3.
(6) 使用应用程序的原始 cookieSECRET_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 ) Compare the calculated result with the signature previously popped out of the just received cookie. If they match, we know that the cookie has not been messed with. But if even just a space has been added to the cookie, the signatures won't match.
(7)将计算结果与之前从刚收到的cookie中弹出的签名进行比较。如果它们匹配,我们就知道 cookie 没有被弄乱。但是,即使只是在 cookie 中添加了一个空格,签名也不会匹配。
# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature
( 8 ) If they don't match then you may respond with any number of actions, log the event, discard the cookie, issue a fresh one, redirect to a login page, etc.
( 8 ) 如果它们不匹配,那么您可以使用任意数量的操作进行响应,记录事件,丢弃 cookie,发出新的 cookie,重定向到登录页面等。
>>> if not good_cookie:
... security_log(cookie)
Hash-based Message Authentication Code (HMAC)
基于散列的消息认证码 (HMAC)
The type of signature generated above that requires a secret key to ensure the integrity of some contents is called in cryptography a Message Authentication Codeor MAC.
上面生成的需要密钥来确保某些内容完整性的签名类型在密码学中称为消息身份验证代码或MAC。
I specified earlier that the example above is an oversimplification of that concept and that it wasn't a good idea to implement your own signing. That's because the algorithm used to sign cookies in Flask is called HMACand is a bit more involved than the above simple step-by-step. The general idea is the same, but due to reasons beyond the scope of this discussion, the series of computations are a tad bit more complex. If you're still interested in crafting a DIY, as it's usually the case, Python has some modules to help you get started :) here's a starting block:
我之前指出,上面的示例过于简化了该概念,实现自己的签名并不是一个好主意。那是因为在 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()
The documentaton for hmacand hashlib.
The "Demystification" of SECRET_KEY:)
SECRET_KEY:)的“解密”
What's a "signature" in this context?
在这种情况下,什么是“签名”?
It's a method to ensure that some content has not been modified by anyone other than a person or an entity authorized to do so.
这是一种确保某些内容未被授权的个人或实体以外的任何人修改的方法。
One of the simplest forms of signature is the "checksum", which simply verifies that two pieces of data are the same. For example, when installing software from source it's important to first confirm that your copy of the source code is identical to the author's. A common approach to do this is to run the source through a cryptographic hash function and compare the output with the checksum published on the project's home page.
最简单的签名形式之一是“校验和”,它只是验证两段数据是否相同。例如,当从源代码安装软件时,首先要确认您的源代码副本与作者的相同,这一点很重要。执行此操作的常用方法是通过加密哈希函数运行源,并将输出与项目主页上发布的校验和进行比较。
Let's say for instance that you're about to download a project's source in a gzipped file from a web mirror. The SHA1 checksum published on the project's web page is 'eb84e8da7ca23e9f83....'
例如,假设您要从 Web 镜像下载 gzip 文件中的项目源。项目网页上发布的 SHA1 校验和为“eb84e8da7ca23e9f83....”
# 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....
Both hashes are the same, you know that you have an identical copy.
两个哈希是相同的,你知道你有一个相同的副本。
What's a cookie?
什么是饼干?
An extensive discussion on cookies would go beyond the scope of this question. I provide an overview here since a minimal understanding can be useful to have a better understanding of how and why SECRET_KEYis useful. I highly encourage you to follow up with some personal readings on HTTP Cookies.
关于 cookie 的广泛讨论超出了这个问题的范围。我在这里提供一个概述,因为最低限度的理解可能有助于更好地理解如何以及为什么SECRET_KEY有用。我强烈建议您继续阅读有关 HTTP Cookie 的一些个人阅读材料。
A common practice in web applications is to use the client (web browser) as a lightweight cache. Cookies are one implementation of this practice. A cookie is typically some data added by the server to an HTTP response by way of its headers. It's kept by the browser which subsequently sends it back to the server when issuing requests, also by way of HTTP headers. The data contained in a cookie can be used to emulate what's called statefulness, the illusion that the server is maintaining an ongoing connection with the client. Only, in this case, instead of a wire to keep the connection "alive", you simply have snapshots of the state of the application after it has handled a client's request. These snapshots are carried back and forth between client and server. Upon receiving a request, the server first reads the content of the cookie to reestablish the context of its conversation with the client. It then handles the request within that context and before returning the response to the client, updates the cookie. The illusion of an ongoing session is thus maintained.
Web 应用程序中的常见做法是将客户端(Web 浏览器)用作轻量级缓存。Cookie 是这种做法的一种实现。cookie 通常是服务器通过其标头添加到 HTTP 响应的一些数据。它由浏览器保存,随后在发出请求时也通过 HTTP 标头将其发送回服务器。cookie 中包含的数据可用于模拟所谓的状态,服务器与客户端保持持续连接的错觉。只是,在这种情况下,您只需在应用程序处理客户端请求后获得应用程序状态的快照,而不是保持连接“活动”的连线。这些快照在客户端和服务器之间来回传送。收到请求后,服务器首先读取 cookie 的内容,以重新建立与客户端的对话上下文。然后它在该上下文中处理请求,并在将响应返回给客户端之前更新 cookie。因此保持了正在进行的会话的错觉。
What does a cookie look like?
饼干是什么样子的?
A typical cookie would look like this:
典型的 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
Cookies are trivial to peruse from any modern browser. On Firefox for example go to Preferences > Privacy > History > remove individual cookies.
从任何现代浏览器中仔细阅读 Cookie 都是微不足道的。例如,在 Firefox 上,转到Preferences > Privacy > History > remove individual cookies。
The contentfield is the most relevant to the application. Other fields carry mostly meta instructions to specify various scopes of influence.
该content字段与应用程序最相关。其他字段主要携带元指令来指定各种影响范围。
Why use cookies at all?
为什么要使用cookies?
The short answer is performance. Using cookies, minimizes the need to look things up in various data stores (memory caches, files, databases, etc), thus speeding things up on the server application's side. Keep in mind that the bigger the cookie the heavier the payload over the network, so what you save in database lookup on the server you might lose over the network. Consider carefully what to include in your cookies.
简短的回答是性能。使用 cookie,最大限度地减少在各种数据存储(内存缓存、文件、数据库等)中查找的需要,从而加快服务器应用程序端的处理速度。请记住,cookie 越大,网络上的负载越重,因此您在服务器上的数据库查找中保存的内容可能会在网络上丢失。仔细考虑要包含在您的 cookie 中的内容。
Why would cookies need to be signed?
为什么需要对 cookie 进行签名?
Cookies are used to keep all sorts of information, some of which can be very sensitive. They're also by nature not safe and require that a number of auxiliary precautions be taken to be considered secure in any way for both parties, client and server. Signing cookies specifically addresses the problem that they can be tinkered with in attempts to fool server applications. There are other measures to mitigate other types of vulnerabilities, I encourage you to read up more on cookies.
Cookie 用于保存各种信息,其中一些信息可能非常敏感。它们本质上也不安全,需要采取一些辅助预防措施,以确保双方、客户端和服务器以任何方式安全。签名 cookie 专门解决了可以修补它们以试图欺骗服务器应用程序的问题。还有其他措施可以缓解其他类型的漏洞,我鼓励您阅读更多关于 cookie 的信息。
How can a cookie be tampered with?
如何篡改cookie?
Cookies reside on the client in text form and can be edited with no effort. A cookie received by your server application could have been modified for a number of reasons, some of which may not be innocent. Imagine a web application that keeps permission information about its users on cookies and grants privileges based on that information. If the cookie is not tinker-proof, anyone could modify theirs to elevate their status from "role=visitor" to "role=admin" and the application would be none the wiser.
Cookie 以文本形式存在于客户端,可以轻松编辑。您的服务器应用程序接收到的 cookie 可能因多种原因而被修改,其中一些可能并非无辜。想象一个 Web 应用程序,它在 cookie 上保存有关其用户的权限信息,并根据该信息授予权限。如果 cookie 不是防修补的,任何人都可以修改他们的 cookie 以将他们的状态从“role=visitor”提升到“role=admin”,应用程序也不会更聪明。
Why is a
SECRET_KEYnecessary to sign cookies?
为什么
SECRET_KEY需要对 cookie 进行签名?
Verifying cookies is a tad bit different than verifying source code the way it's described earlier. In the case of the source code, the original author is the trustee and owner of the reference fingerprint (the checksum), which will be kept public. What you don't trust is the source code, but you trust the public signature. So to verify your copy of the source you simply want your calculated hash to match the public hash.
验证 cookie 与以前面描述的方式验证源代码有点不同。在源代码的情况下,原作者是参考指纹(校验和)的受托人和所有者,该指纹将被公开。您不信任的是源代码,但您信任公共签名。因此,要验证您的源副本,您只需要计算出的散列与公共散列相匹配。
In the case of a cookie however the application doesn't keep track of the signature, it keeps track of its SECRET_KEY. The SECRET_KEYis the reference fingerprint. Cookies travel with a signature that they claim to be legit. Legitimacy here means that the signature was issued by the owner of the cookie, that is the application, and in this case, it's that claim that you don't trust and you need to check the signature for validity. To do that you need to include an element in the signature that is only known to you, that's the SECRET_KEY. Someone may change a cookie, but since they don't have the secret ingredient to properly calculate a valid signature they cannot spoof it. As stated a bit earlier this type of fingerprinting, where on top of the checksum one also provides a secret key, is called a Message Authentication Code.
但是,对于 cookie,应用程序不会跟踪签名,而是跟踪其SECRET_KEY. 的SECRET_KEY是参考指纹。Cookie 带有他们声称合法的签名。此处的合法性意味着签名是由 cookie 的所有者(即应用程序)发布的,在这种情况下,它表示您不信任并且需要检查签名的有效性。为此,您需要在签名中包含一个只有您知道的元素,即SECRET_KEY. 有人可能会更改 cookie,但由于他们没有正确计算有效签名的秘密成分,因此他们无法欺骗它。如前所述,这种类型的指纹识别,在校验和之上还提供了一个秘密密钥,
What about Sessions?
会话呢?
Sessions in their classical implementation are cookies that carry only an ID in the contentfield, the session_id. The purpose of sessions is exactly the same as signed cookies, i.e. to prevent cookie tampering. Classical sessions have a different approach though. Upon receiving a session cookie the server uses the ID to look up the session data in its own local storage, which could be a database, a file, or sometimes a cache in memory. The session cookie is typically set to expire when the browser is closed. Because of the local storage lookup step, this implementation of sessions typically incurs a performance hit. Signed cookies are becoming a preferred alternative and that's how Flask's sessions are implemented. In other words, Flask sessions aresigned cookies, and to use signed cookies in Flask just use its SessionAPI.
会话在其经典实现中是仅在content字段中携带 ID 的 cookie session_id。会话的目的与签名 cookie 完全相同,即防止 cookie 篡改。经典会话有不同的方法。收到会话 cookie 后,服务器使用 ID 在自己的本地存储中查找会话数据,本地存储可以是数据库、文件,有时也可以是内存中的缓存。会话 cookie 通常设置为在浏览器关闭时过期。由于本地存储查找步骤,会话的这种实现通常会导致性能下降。签名 cookie 正在成为首选的替代方案,这就是 Flask 会话的实现方式。换句话说,Flask 会话是签名 cookie,在 Flask 中使用签名 cookie 只需使用它的SessionAPI。
Why not also encrypt the cookies?
为什么不加密 cookie?
Sometimes the contents of cookies can be encrypted before also being signed. This is done if they're deemed too sensitive to be visible from the browser (encryption hides the contents). Simply signing cookies however, addresses a different need, one where there's a desire to maintain a degree of visibility and usability to cookies on the browser, while preventing that they'd be meddled with.
有时 cookie 的内容可以在被签名之前加密。如果它们被认为太敏感而无法从浏览器中看到(加密隐藏内容),则会执行此操作。然而,简单地签署 cookie 可以满足不同的需求,即希望在浏览器上保持 cookie 一定程度的可见性和可用性,同时防止它们被干预。
What happens if I change the
SECRET_KEY?
如果我更改
SECRET_KEY?
By changing the SECRET_KEYyou're invalidating allcookies signed with the previous key. When the application receives a request with a cookie that was signed with a previous SECRET_KEY, it will try to calculate the signature with the new SECRET_KEY, and both signatures won't match, this cookie and all its data will be rejected, it will be as if the browser is connecting to the server for the first time. Users will be logged out and their old cookie will be forgotten, along with anything stored inside. Note that this is different from the way an expired cookie is handled. An expired cookie may have its lease extended if its signature checks out. An invalid signature just implies a plain invalid cookie.
通过更改,SECRET_KEY您将使所有使用前一个密钥签名的 cookie失效。当应用程序收到一个请求时,它的 cookie 是用前一个签名的SECRET_KEY,它会尝试用新的签名来计算签名,如果SECRET_KEY两个签名不匹配,这个 cookie 和它的所有数据都将被拒绝,就好像浏览器是第一次连接到服务器。用户将被注销,他们的旧 cookie 以及存储在其中的任何内容都将被遗忘。请注意,这与处理过期 cookie 的方式不同。如果其签名签出,则过期的 cookie 可能会延长其租期。一个无效的签名仅仅意味着一个简单的无效 cookie。
So unless you want to invalidate all signed cookies, try to keep the SECRET_KEYthe same for extended periods.
因此,除非您想让所有已签名的 cookie 无效,否则请尝试SECRET_KEY长时间保持不变。
What's a good
SECRET_KEY?
什么是好
SECRET_KEY?
A secret key should be hard to guess. The documentation on Sessionshas a good recipe for random key generation:
密钥应该很难猜到。Sessions上的文档有一个很好的随机密钥生成方法:
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
You copy the key and paste it in your configuration file as the value of SECRET_KEY.
您复制该密钥并将其作为 的值粘贴到您的配置文件中SECRET_KEY。
Short of using a key that was randomly generated, you could use a complex assortment of words, numbers, and symbols, perhaps arranged in a sentence known only to you, encoded in byte form.
除了使用随机生成的密钥之外,您还可以使用复杂的词、数字和符号分类,这些词可能排列在只有您知道的句子中,以字节形式编码。
Do notset the SECRET_KEYdirectly with a function that generates a different key each time it's called. For example, don't do this:
不要不设置SECRET_KEY与生成每个这就是所谓的时间不同的键的功能直接。例如,不要这样做:
# this is not good
SECRET_KEY = random_key_generator()
Each time your application is restarted it will be given a new key, thus invalidating the previous.
每次您的应用程序重新启动时,它都会获得一个新密钥,从而使之前的密钥无效。
Instead, open an interactive python shell and call the function to generate the key, then copy and paste it to the config.
相反,打开一个交互式 python shell 并调用函数来生成密钥,然后将其复制并粘贴到配置中。

