django 中是否有生成 settings.SECRET_KEY 的函数?

Is there a function for generating settings.SECRET_KEY in django?

我写了一个 ansible-role for openwisp2 to ease its deployment, it's a series of django apps. To ease the deployment as much as possible, I wrote a simple (probably trivial) SECRET_KEY generator script ,ansible 第一次调用它来生成密钥 运行.

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

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

这将避免这种自制的解决方案,即使它们有效,但在安全方面并不有效。

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

但请注意,它与您的版本差别不大。

请注意,这在生产中使用可能不安全,正如 S Ghosh 在下面的 post 中指出的那样。但是复制并粘贴到 运行 django-admin shell 之后,例如快速获取密钥。

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

运行 下面这个命令在终端上。

$ 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

我想补充一点,根据提交 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

S Ghosh TLDR: Generate Django Secret Key indicates that as of version 3.1.3, Django is actually using the Python secrets module behind the scenes. Looking at this blob for get_random_secret_key and this other blobget_random_string引用的post,我看是这样的:

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,最大的问题是您是否要生成依赖 Dango 的 SECRET_KEY,或者只是 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'