更改 Django 的 SECRET_KEY 的效果
Posted
技术标签:
【中文标题】更改 Django 的 SECRET_KEY 的效果【英文标题】:Effects of changing Django's SECRET_KEY 【发布时间】:2013-02-16 17:10:57 【问题描述】:我犯了一个错误,将我的 Django 项目的 SECRET_KEY
提交到公共存储库中。
这个密钥应该保密according to the docs。
Django 项目已经上线,并且已经有一些活跃用户运行了一段时间。如果我更改SECRET_KEY
会有什么影响?任何现有的用户、cookie、会话等会受到影响吗?显然,新的SECRET_KEY
将不再存储在公共位置。
【问题讨论】:
【参考方案1】:根据这个页面https://docs.djangoproject.com/en/dev/topics/signing/,SECRET_KEY 主要用于临时性的东西——例如对通过网络发送的数据进行签名,以便您可以检测到篡改。看起来可能会破坏的东西是:
签名的 cookie,例如“记住我在这台计算机上的身份验证”类型值。在这种情况下,cookie 将失效,签名将无法验证,用户将不得不重新验证。 对于请求密码重置或自定义文件下载链接的任何用户,这些链接将不再有效。用户只需重新请求这些链接。比我有更新和/或突出 Django 经验的人可能会提出其他意见,但我怀疑除非您明确使用签名 API 做某事,否则这只会给您的用户带来轻微的不便。
【讨论】:
那为什么不在每次服务器重启时生成一个新的密钥呢? 如果您使用多个进程运行同一台服务器,这可能会导致问题。 @osa 你想在每次推送代码/重启服务器时注销所有用户吗?【参考方案2】:SECRET_KEY 字符串主要用于加密和/或散列 cookie 数据。由于默认会话 cookie 有其自身的缺点,因此很多框架(包括 Django)都会这样做。
想象一下,您在 django 中有一个表单,用于编辑带有隐藏字段的文章。在此隐藏字段中存储您正在编辑的文章的 ID。如果您想确保没有人可以向您发送任何其他文章 ID,您将添加一个带有散列 ID 的额外隐藏字段。因此,如果有人更改 ID,您会知道,因为哈希值不会相同。
当然这是一个简单的例子,但这就是 SECRET_KEY 的使用方式。
Django 在内部使用它,例如 % csrf_token % 和其他一些东西。如果您根据您的问题和您没有使用它来更改它,那么它确实不会对您的应用程序产生任何影响。
唯一的问题是可能会话值将被丢弃。因此,例如用户将不得不再次登录管理员,因为 django 将无法使用不同的密钥解码会话。
【讨论】:
【参考方案3】:编辑:此答案基于 django 1.5
SECRET_KEY
用在很多不同的地方,我会先指出受它影响的内容,然后尝试查看该列表并给出影响的准确解释。
直接或间接使用SECRET_KEY
的事物列表:
startproject
create CSRF key
实际上,这里列出的许多项目都使用SECRET_KEY
到django.utils.crypt.get_random_string()
,它们使用它来播种随机引擎。这不会受到 SECRET_KEY
值更改的影响。
价值变化直接影响的用户体验有:
会话,数据解码将中断,这对任何会话后端(cookie、数据库、基于文件或缓存)都有效。 已发送的密码重置令牌将不起作用,用户必须要求一个新令牌。 cmets 表单(如果使用django.contrib.comments
)将不会验证是否在值更改之前请求并在值更改之后提交。我认为这非常轻微,但可能会让用户感到困惑。
消息(来自django.contrib.messages
)不会在与 cmets 表单相同的时间条件下验证服务器端。
更新:现在正在使用 django 1.9.5,快速查看源代码给了我几乎相同的答案。以后可能会进行彻底的检查。
【讨论】:
我正在更改本地开发服务器上的 SECRET_KEY 并且不会将我注销,因此更改后似乎至少会话(缓存)可以正常工作。您能否进一步详细说明data decode will break
的含义,并指出一些会中断的代码(在 django 或示例项目中)?编辑:仍在使用 django 1.4 - 是这样吗?
@teferi 我不知道 1.4,这是看代码的问题。我指出了每个点的所有来源,您可以查看“保护会话数据并创建随机会话密钥”。您仍然处于登录状态是正常的,但您将无法读取会话中包含的数据,因为 SECRET_KEY
用于 salted_hmac
用于对会话数据进行哈希处理。
@Henning 我不这么认为。 auth_user 中的passwords are stored 与<algorithm>$<iterations>$<salt>$<hash>
一样,因此在每种情况下,随机盐都与密码一起存储。
在 Django 版本 > 1.5 中,答案会显着不同吗? (例如现在的 1.9)
@sberder 你能根据最新的 django 版本更新答案吗?【参考方案4】:
自从提出这个问题后,Django documentation 已更改为包含答案。
密钥用于:
如果您使用除django.contrib.sessions.backends.cache
之外的任何其他会话后端,或者使用默认的get_session_auth_hash()
,则为所有会话。 如果您使用的是CookieStorage
或FallbackStorage
,则为所有消息。 所有PasswordResetView
令牌。 加密签名的任何使用,除非提供不同的密钥。如果您轮换您的密钥,上述所有内容都将失效。密钥不用于用户的密码,密钥轮换不会影响他们。
我不清楚应该如何轮换密钥。我找到了关于 Django generates a key for a new project 的讨论,以及讨论 other options 的 Gist。我最终决定让 Django 创建一个新项目,将新密钥复制到我的旧项目中,然后擦除新项目。
cd ~/junk # Go to some safe directory to create a new project.
django-admin startproject django_scratch
grep SECRET_KEY django_scratch/django_scratch/settings.py # copy to old project
rm -R django_scratch
更新
看起来 Django 在 1.10 版本中添加了get_random_secret_key()
function。您可以使用它来生成新的密钥。
$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
s!)5@5s79sp=92a+!f4v!1g0d0+64ln3d$xm1f_7=749ht&-zi
$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
_)+%kymd=f^8o_fea1*yro7atz3w+5(t2/lm2cz70*e$2mn\g3
$
【讨论】:
秘钥生成是否依赖秘钥? 不,@kdazzle,如果您查看source code forstartproject
,您会发现它只是使用crypto
模块生成一个随机字符串。
嘿,对不起,@DonKirkby,开个玩笑
@kdazzle 一直是秘钥【参考方案5】:
我犯了同样的错误。默认密码是 50 长,所以我使用 powershell 生成了一个 50 长的随机字符串,并用它替换了旧的 SECRET_KEY。我已登录,更换 SECRET_KEY 后,我之前的会话已失效。
使用 Powershell (source):
# Load the .net System.Web namespace which has the GeneratePassword function
[Reflection.Assembly]::LoadWithPartialName("System.Web")
# GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
[System.Web.Security.Membership]::GeneratePassword(50,5)
使用 Bash (source):
# tr includes ABCabc123 and the characters from OWASP's "Password special characters list"
cat /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&\''()*+,-./:;<=>?@[\]^_`|~' | head -c 100 ; echo
此时我想为什么不尝试更大的密钥,所以我尝试了 100 和 1000 长密钥。两者都有效。如果我理解source code,则签名函数返回的对象是base64 中的hmac 哈希。 RFC 2104 对所需的 HMAC 密钥长度有这样的说法。
使用密钥时间更长的应用程序 比 B 字节将首先使用 H 散列密钥,然后使用 生成的 L 字节字符串作为 HMAC 的实际密钥。
HMAC 的密钥可以是任意长度(长度超过 B 字节的密钥是 首先使用 H) 进行哈希处理。然而,小于 L 字节是强 气馁,因为它会降低安全强度 功能。长度超过 L 字节的密钥是可以接受的,但额外的 长度不会显着增加功能强度。 (一种 如果密钥的随机性为 被认为是弱者。)
要翻译成普通话,密钥的大小需要与输出的大小相同。密钥也需要以位为单位。 base64 中的每个数字代表 6 位。因此,如果您有一个 50 个字符的密码,那么您将拥有一个 50 x 6 = 300 位的密钥。如果您使用的是 SHA256,那么您需要一个 256 位密钥(sha256 根据定义使用 256 位)。因此,除非您打算使用大于 SHA256 的散列算法,否则 50 长的密码应该可以工作。
但是由于密钥中的任何额外位都会被散列,因此它的大小不会显着降低性能。但它会保证你有足够的位来处理更大的散列函数。 SHA-512 将被 100 长的 SECRET_KEY 覆盖(50 x 6 = 600 位 > 512 位)。
【讨论】:
以上是关于更改 Django 的 SECRET_KEY 的效果的主要内容,如果未能解决你的问题,请参考以下文章
Django出现Session data corrupted的原因?
在 django 中是不是有生成 settings.SECRET_KEY 的功能?
django.core.exceptions.ImproperlyConfigured:设置 SECRET_KEY 环境变量