在 django 中是不是有生成 settings.SECRET_KEY 的功能?

Posted

技术标签:

【中文标题】在 django 中是不是有生成 settings.SECRET_KEY 的功能?【英文标题】:Is there a function for generating settings.SECRET_KEY in django?在 django 中是否有生成 settings.SECRET_KEY 的功能? 【发布时间】:2017-05-09 00:18:39 【问题描述】:

我写了一个ansible-role for openwisp2 来简化它的部署,它是一系列django 应用程序。为了尽可能简化部署,我编写了一个简单的(可能是微不足道的)SECRET_KEY generator script,在 ansible playbook 第一次运行时,ansible 会调用它来生成密钥。

现在,这很好用,但我认为它破坏了 Django 在生成强密钥方面的内置安全措施,这也很难猜到。

当时看了其他的方法但是没找到太多,现在想知道:django有生成settings.SECRET_KEY的函数吗?

这样就可以避免这种自制的解决方案,即使它们有效,但在安全性方面却无效。

【问题讨论】:

【参考方案1】:

S Ghosh TLDR: Generate Django Secret Key 引用的帖子表明,截至 3.1.3 版本,Django 实际上在后台使用 Python secrets 模块。查看this blob 对应get_random_secret_key 和this other blob 对应get_random_string,我可以看到是这样的:

def get_random_secret_key():
    """
    Return a 50 character random string usable as a SECRET_KEY setting value.
    """
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
    return get_random_string(50, chars)
def get_random_string(length, allowed_chars=RANDOM_STRING_CHARS):
    """
    Return a securely generated random string.
    The bit length of the returned value can be calculated with the formula:
        log_2(len(allowed_chars)^length)
    For example, with default `allowed_chars` (26+26+10), this gives:
      * length: 12, bit length =~ 71 bits
      * length: 22, bit length =~ 131 bits
    """
    return ''.join(secrets.choice(allowed_chars) for i in range(length))

我在代码中看到的get_random_secret_key 函数的唯一问题是允许的字符不包括大写字母,因此相同大小密钥的可能位数小于大写字母时的位数包括,但不多:

from math import log2
lower_plus_numbers = (list(chr(o) for o in range(0x61, 0x7B))
                      + list(chr(o) for o in range(0x30, 0x3A)))
punctuation = list('!@#$%^&*(-_=+)')
upper_alpha = list(chr(o) for o in range(0x41, 0x5B))
shorter = log2((len(lower_plus_numbers) + len(punctuation)) ** 50)
longer = log2((len(lower_plus_numbers) + len(punctuation) + len(upper_alpha)) ** 50)
print(f'longer: int(longer + 0.5); shorter: int(shorter + 0.5) '
      f'difference: int(longer - shorter + 0.5); ratio: longer/shorter')

以上代码的输出:

longer: 312; shorter: 282; difference: 30; ratio: 1.1070316647619918

所以,如果你有足够新的 Django 和 Python,最大的问题是你是想生成你的 SECRET_KEY 依赖于 Dango,还是只生成 Python。如果您不介意 Django 依赖,但想要包含大写字母,或者想要更长的键,您可以轻松地执行以下操作:

from django.utils.crypto import get_random_string
key_length = 60
get_random_string(
    key_length,
    allowed_chars=lower_plus_numbers + punctuation + upper_alpha,
)

样本输出:

'gW(VDtylhoAuZNcLbIC=ai5=2*tPZ=Gmf4D1^4T!NxX3tB0%_w7pYY2+FgDx'

如果您不想要 Django 依赖项,您可以使用 S Ghosh 的答案。或者,如果您想要的不仅仅是十六进制字符,您可以执行以下操作:

allowed_chars = [chr(i) for i in range(0x21, 0x7F)]
key_length = 60
key = ''.join(secrets.choice(allowed_chars) for i in range(key_length))

key 的值(作为 python 字符串):

'DN7tbWid#q6R^=%i"[1AA>$@AZg=XD+p|[aB?:#V`:kKWL77P6dC,~(\\9O\'j'

【讨论】:

【参考方案2】:

我想补充一点,根据提交Fixed #31757 -- Adjusted system check for SECRET_KEY to warn about autogenerated default keys,方法get_random_secret_key() 被认为是不安全的。

如果您使用的是 python 3.6+,那么您可以使用 secrets.token_hex([nbytes=None]) 函数

python3 -c 'import secrets; print(secrets.token_hex(100))'

信用TLDR: Generate Django Secret Key

【讨论】:

【参考方案3】:

在终端上运行以下命令。

$ python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'

输出:

2x$e%!k_u_0*gq0s4!_u(2(^lpy&gir0hg)q&5nurj0-sseuav

【讨论】:

【参考方案4】:

对于像我这样的懒人:

from django.core.management.utils import get_random_secret_key  
get_random_secret_key()

【讨论】:

不懒惰。实用;)【参考方案5】:

确实,您可以使用与调用startproject 时生成新密钥相同的函数,即django.core.management.utils.get_random_secret_key()

请注意,它与您的版本并没有太大区别。

【讨论】:

我认为它内置了更多安全性,但我错了。无论如何,使用该功能可能会更好,因为将来可能会对其进行改进。 其实get_random_string 比我的版本好一点:github.com/django/django/blob/master/django/utils/… 在settings.py中写可以吗? SECRET_KEY=django.core.management.utils.get_random_secret_key() @Psddp 你可以这样做,但这意味着每次你的应用程序启动/重新启动时,你都会获得一个新的密钥,这意味着所有现有的会话、cookie 等都将失效.如果这不是您使用或关心的东西,那么它可能会起作用,但仍然感觉不应该这样做。

以上是关于在 django 中是不是有生成 settings.SECRET_KEY 的功能?的主要内容,如果未能解决你的问题,请参考以下文章

eclipse中是不是有生成资源的快捷方式(构造函数,get/set .....)

Django使用数据库表反向生成models类

Django ManyToMany 字段的 set() 操作是不是清除现有关系?

django 有model生成SQL以及现有反向表生成model

id 主键是不是必须在从 inspectdb 针对现有数据库生成的 Django 模型中显式定义?

从数据库反向生成django项目中的models文件