更改Django的SECRET_KEY的影响


202

我犯了一个错误,并将Django项目SECRET_KEY提交到公共存储库中。

根据文档https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY,此密钥应保持秘密

Django项目已经启动,并且已经有一些活跃用户运行了一段时间。如果更改,会产生什么影响SECRET_KEY?现有的用户,Cookie,会话等是否会受到影响?显然,新产品SECRET_KEY将不再存储在公共场所。

Answers:


199

编辑:此答案基于Django 1.5

SECRET_KEY 在很多地方都使用过该工具,我将首先指出它会受到什么影响,然后尝试遍历该列表并给出影响的精确解释。

SECRET_KEY直接或间接使用的事物列表:

实际上,这里列出的许多项目都可以SECRET_KEY通过django.utils.crypt.get_random_string()它来为随机引擎提供种子。不会受到值更改的影响SECRET_KEY

价值变化直接影响的用户体验是:

  • 会话,数据解码将中断,这对于任何会话后端(cookie,数据库,基于文件或缓存)均有效。
  • 已发送的密码重置令牌无效,用户将不得不询问一个新的密码。
  • 注释表单(如果使用django.contrib.comments)将无法验证它是否在值更改之前被请求并在值更改之后被提交。我认为这是非常小的,但可能会使用户感到困惑。
  • (来自django.contrib.messages)的消息将无法在与注释表单相同的时间条件下验证服务器端。

更新:现在可以在Django 1.9.5上运行,快速查看源代码可以得到几乎相同的答案。以后可能要进行彻底检查。


1
我正在更改本地开发服务器上的SECRET_KEY,但并没有注销我,因此看来更改后至少session(cache)可以正常工作。您能否进一步说明您的意思data decode will break,或者指出一些可能会破坏代码(在Django或示例项目中)?编辑:仍在使用django 1.4-是这种情况吗?
Kirill Zaitsev 2013年

@teferi我不了解1.4,这是看代码的问题。我指出了每个点的所有来源,可以看看“保护会话数据并创建随机会话密钥”。您仍然登录是正常的,但是您无法读取会话中包含的数据SECRET_KEY(用于salted_hmac对会话数据进行哈希处理)。
sberder

如果将其用于密码哈希盐,这是否意味着必须重置数据库中的密码?
亨宁

7
@亨宁我不这么认为。该密码存储<algorithm>$<iterations>$<salt>$<hash>在AUTH_USER,所以随机盐一同存储在每种情况下的密码。
Denis Drescher 2014年

2
对于Django版本> 1.5,答案会大不相同吗?(例如当前的1.9)
das-g

36

自从提出此问题以来,Django文档已更改为包含答案。

密钥用于:

  • 如果您使用的会话后端不是django.contrib.sessions.backends.cache或使用默认会话,则所有会话get_session_auth_hash()
  • 如果使用CookieStorage或,则显示所有消息FallbackStorage
  • 所有PasswordResetView令牌。
  • 加密签名的任何用法,除非提供了不同的密钥。

如果您旋转密钥,以上所有内容将失效。秘密密钥不用于用户密码,密钥旋转不会影响它们。

我不清楚我该如何旋转密钥。我找到了关于Django如何为新项目生成密钥的讨论,以及讨论其他选项的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()功能。您可以使用它来生成新的密钥。

$ ./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
$

4
密钥生成是否依赖于密钥?
kdazzle,2015年

4
不,@ kdazzle,如果您查看的源代码startproject,您会发现它只是使用crypto模块生成了一个随机字符串。
Don Kirkby 2015年

12
嘿,对不起,@ DonKirkby,恶作剧
kdazzle 2015年

16

根据此页面https://docs.djangoproject.com/en/dev/topics/signing/,SECRET_KEY主要用于临时性内容-对通过网络发送的数据进行签名,以便例如检测篡改。看起来可能会中断的事情是:

  • 已签名的cookie,例如“在此计算机上记住我的身份验证”类型的值。在这种情况下,cookie将失效,签名将无法验证,用户将不得不重新进行身份验证。
  • 对于请求密码重置或自定义文件下载链接的任何用户,这些链接将不再有效。用户只需要重新请求那些链接。

可能有比我更早和/或重要的Django经验的人,但是我怀疑除非您明确地使用签名API进行操作,否则这只会给用户带来不便。


6
那么,为什么不在每次重启服务器时生成一个新密钥呢?
osa 2014年

4
如果您使用多个进程运行同一服务器,则可能会引起问题。
dbn

1
@osa您想在每次输入代码/重新启动服务器时注销所有用户吗?
EralpB

6

SECRET_KEY字符串主要用于加密和/或哈希Cookie数据。许多框架(包括Django)都可以使用此功能,因为默认会话cookie具有其自身的缺点。

想象一下,您在django中具有用于编辑带有隐藏字段的文章的表单。在此隐藏字段中存储了您正在编辑的文章的ID。而且,如果您想确保没有人可以向您发送任何其他文章ID,则将添加一个带有哈希ID的额外隐藏字段。因此,如果有人更改ID,您将知道它,因为哈希不会相同。

当然,这是一个简单的示例,但这就是SECRET_KEY的使用方式。

Django内部使用它,例如用于{%csrf_token%}和其他一些东西。如果您根据自己的问题并且未使用它来进行更改,那么它实际上不会对您的应用程序产生任何影响。

唯一的是,可能会删除会话值。因此,例如,用户将不得不再次登录admin,因为django将无法使用其他密钥来解码会话。


1

我犯了同样的错误。默认密码为50长,因此我使用powershell生成了50长的随机字符串,并用它替换了旧的SECRET_KEY。我已登录,并且在替换SECRET_KEY之后,我之前的会话已失效。

使用Powershell(来源):

# 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(来源):

# 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长的密钥。两者都起作用。如果我理解源代码,则签名者函数返回的对象是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位)覆盖。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.