【问题标题】: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的函数吗?

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

【问题讨论】:

    标签: django django-settings


    【解决方案1】:

    S Ghosh TLDR: Generate Django Secret Key 引用的帖子表明,截至 3.1.3 版本,Django 实际上在后台使用 Python secrets 模块。查看this blob 对应get_random_secret_keythis 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 等都将失效.如果这不是您使用或关心的东西,那么它可能会起作用,但仍然感觉不应该这样做。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-03-01
          • 1970-01-01
          • 2015-03-04
          • 2017-06-26
          • 1970-01-01
          • 1970-01-01
          • 2023-04-05
          相关资源
          最近更新 更多