【问题标题】:Where to store secret keys DJANGO在哪里存储密钥 DJANGO
【发布时间】:2013-02-19 00:54:56
【问题描述】:

为了我的一生,我一直在到处寻找这个,但没有找到答案。我希望我不会重复发布。

建议您将密钥保存在与常规 settings.py 不同的文件中。此外,您永远不应该提交包含诸如 SECRET_KEY、AWS_SECRET_KEY 等密钥的“secret.py”文件。

我的问题是:在您的生产服务器中,您需要引用您的密钥,这意味着您的“secret.py”设置文件应该位于服务器周围的某个地方,对吗?如果是这样,您如何在生产中保护您的密钥?

【问题讨论】:

    标签: django django-settings


    【解决方案1】:

    我想添加一个新答案,因为作为初学者,之前接受的答案对我来说没有多大意义(这只是难题的一部分)。

    以下是我在本地和生产环境(Heroku 等)中存储密钥的方式。

    注意:只有在您计划将项目上线时才真正需要这样做。如果只是本地项目,则不需要。

    我还为喜欢这种格式的人创建了video tutorial

    1) 安装 python-dotenv 以创建本地项目环境来存储您的密钥。

    pip install python-dotenv
    

    2) 在您的基本目录(manage.py 所在的位置)中创建一个.env 文件。

    YourDjangoProject
    ├───project
    │   ├───__init__.py
    │   ├───asgi.py
    │   ├───settings.py
    │   ├───urls.py
    │   └───wsgi.py
    ├───.env
    ├───manage.py
    └───db.sqlite3
    

    如果你有一个 Heroku 项目,它应该看起来像这样:

    YourDjangoProject
    ├───.git
    ├───project
    │   ├───__init__.py
    │   ├───asgi.py
    │   ├───settings.py
    │   ├───urls.py
    │   └───wsgi.py
    ├───venv
    ├───.env
    ├───.gitignore
    ├───manage.py
    ├───Procfile
    ├───requirements.txt
    └───runtime.txt
    

    3) 将.env 添加到您的.gitignore 文件中。

    echo .env > .gitignore  # Or just open your .gitignore and type in .env
    

    这是您保持密钥更安全的方式,因为您不会将 .env 文件上传到 git 或 heroku(或其他任何地方)。

    4) 像这样将 settings.py 文件中的 SECRET_KEY 添加到 .env 文件中(不带引号)

    **Inside of your .env file**
    SECRET_KEY=qolwvjicds5p53gvod1pyrz*%2uykjw&a^&c4moab!w=&16ou7 # <- Example key, SECRET_KEY=yoursecretkey
    

    5) 在您的 settings.py 文件中,添加以下设置:

    import os
    import dotenv # <- New
    
    # Add .env variables anywhere before SECRET_KEY
    dotenv_file = os.path.join(BASE_DIR, ".env")
    if os.path.isfile(dotenv_file):
        dotenv.load_dotenv(dotenv_file)
    
    # UPDATE secret key
    SECRET_KEY = os.environ['SECRET_KEY'] # Instead of your actual secret key
    

    或者,感谢@Ashkay Chandran's answer

    from dotenv import load_dotenv, find_dotenv
    
    load_dotenv(find_dotenv())
    
    SECRET_KEY = os.environ['SECRET_KEY']
    

    现在您的密钥已成功存储在本地。

    更新:我发现你也可以使用 python-decouple 包中的 config 方法,这似乎更容易一些:

    from decouple import config
    
    SECRET_KEY = config('SECRET_KEY')
    
    

    现在您不需要import os 或使用dotenv,因为它会为您处理这些部分并且仍将使用 .env 文件。我开始在我所有的项目中使用它。

    6) 在您的主机(例如 Heroku)上添加 SECRET_KEY 环境变量。


    我主要使用 Heroku 网站,所以如果您想将 Heroku 用于 Django 项目,这部分适合您。

    这假设您已经有一个 Heroku 项目设置并且已经在您的计算机上下载了 Heroku CLI。

    您有 2 个选择:

    1. 从命令行/终端,您可以在项目目录中输入以下命令:
    heroku config:set SECRET_KEY=yoursecretkey # Again, no quotes.
    
    1. 您可以转到 Heroku 仪表板,点击您的应用,转到您的应用设置,然后查看“配置变量”部分,然后点击“显示变量”或“添加变量”并在此处添加您的 SECRET_KEY。

    然后,当您通过 git 将项目推送到 Heroku 时,它应该可以正常工作,没有任何问题。

    就是这样! ?

    这个答案是针对初学者/中级的,希望能消除任何困惑(因为它绝对让我感到困惑)。

    希望这会有所帮助!

    编码愉快。

    【讨论】:

    • 感谢解耦的配置方法。一个提示:你需要安装 pip install python-decouple (而不是 pip install decouple)
    • 感谢python-decouple 的建议。这似乎是最精确的方法。而且正如@alexrogo 提到的,pip install python-decouple 需要先完成。
    【解决方案2】:

    请参阅Django deployment docs for a discussion on this

    有很多生产选项。我这样做的方法是将我的敏感数据变量设置为生产环境中的环境变量。然后我通过os.environ 检索settings.py 中的变量,如下所示:

    import os
    SECRET_KEY = os.environ['SECRET_KEY']
    

    另一个可能的选择是通过部署脚本复制secret.py 文件。

    我确信对于不同的网络服务器还有其他特定的选项。

    【讨论】:

    • 对于 linux:unix.stackexchange.com/questions/21598/…。对于上面的示例,您可以在 .bash_profile.bash_login.profile 中添加 export secret_KEY = 'ABABABABABDSFJKEWLSK' - 取决于存在的情况。
    • 我将我的密钥移动到 .bash_profile 并使用了 os.environ.get,它完全破坏了我的网站,尽管 echo $SECRET_KEY 工作正常。
    • @BabkenVardanyan 这不是真的。只有用户具有读取权限。自己检查stat /proc/$PID/environ
    • @DanHoerst 小提示,在我的机器上删除等号周围的空格没有错误:export secret_KEY='ABABABABABDSFJKEWLSK'
    • @DanHoerst 我试过了,但是我的密钥里面有一个“#”,所以当我把它保存为环境变量时,一切看起来都很好。但是,当我调用它时,它只返回“#”之前的所有内容。有关如何解决此问题的任何想法?
    【解决方案3】:

    您应该以模块化方式存储您的设置。我的意思是把你的设置分散到多个文件中。

    例如,您可以使用base_settings.py 来存储您的所有基本设置; dev_settings.py 用于您的开发服务器设置;最后prod_base_settings.py 用于所有生产设置。所有非基本设置文件都将导入所有基本设置,然后只更改必要的内容:

    # base_settings.py
    ...
    
    # dev_settings.py
    from base_settings import *
    DEBUG = TRUE
    ...
    
    # prod_base_settings.py
    from base_settings import *
    DEBUG = FALSE
    ...
    

    这种方法允许您从不同的设置中获得不同的设置。您还可以提交所有这些文件,除非在生产服务器上您可以创建实际的生产设置文件prod_settings.py,您将在其中指定所有敏感设置。此文件不应在任何地方提交,其内容应保持安全:

    # prod_settings.py
    from prod_base_settings import *
    SECRET_KEY = 'foo'
    

    至于文件名,您可以使用任何您认为合适的文件名。我个人实际上为设置创建了一个 Python 包,然后将各种设置保留在包中:

    project/
      project/
        settings/
          __init__.py
          base.py
          dev.py
          ...
      app1/
        models.py
        ...
      app2/
        models.py
        ...
    

    【讨论】:

    • 感谢您的回复。但是,我正在研究如何保护这些密钥。
    • 将所有机密设置保存在单独的文件中是一种保护它的方式。它仅在文件遭到破坏的情况下服务器被黑客入侵时无法提供保护。但在那种情况下,环境变量只是容易受到攻击,就像我知道的任何其他方法一样。有一些方法可以完全保护此类信息,但所有这些方法都涉及存储安全数据的第三方,然后您的服务器可以向他们询问信息,但为了确保安全,在每次请求时,这些服务都会在您拥有的地方向您发送通知验证请求,因此它们不是完全自动化的。
    • 如何确定要使用哪组设置。某处有“f”吗?在 JS 中,我检查主机名(本地主机或生产服务器)。这样我就有了一个单一的代码库,并且不必记住在部署时进行任何手动更改。
    【解决方案4】:

    我知道这已经很久了,但我刚刚开源了一个小型 Django 应用程序,我正在使用它来生成一个新的密钥,如果它还不存在的话。它被称为django-generate-secret-key

    pip install django-generate-secret-key
    

    然后,在配置/部署运行我的 Django 项目的新服务器时,我运行以下命令(来自 Ansible):

    python manage.py generate_secret_key
    

    简单地说:

    • 检查是否需要生成密钥
    • secretkey.txt 文件中生成它(可自定义)

    那么你需要的就是在你的设置文件中:

    with open('/path/to/the/secretkey.txt') as f:
        SECRET_KEY = f.read().strip()
    

    您现在可以从全自动配置过程中受益无需在您的存储库中存储静态密钥

    【讨论】:

    • 嗯,最新的 django (1.11) 正在获取:FileNotFoundError: [Errno 2] No such file or directory: '/home/.../project/secretkey.txt'
    • @BabkenVardanyan 你是先运行python manage.py generate_secret_key 吗?如果它没有创建文件或者有什么问题,那么请在这里打开一个问题:github.com/MickaelBergem/django-generate-secret-key/issues/new 这样我们可以讨论这个
    • 添加服务器时会发生什么?
    【解决方案5】:

    您应该使用专为分解敏感数据而设计的工具,而不是 if/then 逻辑。我使用 YamJam https://pypi.python.org/pypi/yamjam/ 。它具有 os.environ 方法的所有优点,但更简单——您仍然需要设置这些环境变量,您需要将它们放在某个脚本中。 YamJam 将这些配置设置存储在机器配置存储中,还允许逐个项目覆盖。

    from YamJam import yamjam
    
    variable = yamjam()['myproject']['variable']
    

    是基本用法。和 os.environ 方法一样,它不是特定于框架的,您可以将它与 Django 或任何其他应用程序/框架一起使用。我已经尝试了所有这些,多个 settings.py 文件,if/then 的脆弱逻辑和环境争论。最后还是换了yamjam,没有后悔。

    【讨论】:

      【解决方案6】:

      在环境中存储秘密仍然会将它们放在环境中;如果未经授权的用户可以访问环境,则可以利用它。列出环境变量是一项微不足道的工作,并且命名一个 SECRET 使得对于坏演员不受欢迎的用户来说更加有用和明显。

      然而,秘密在生产中是必要的,那么如何在最小化攻击面的同时访问它们?使用git-secret 之类的工具加密文件中的每个秘密,然后允许授权用户读取文件,如django's docs 中所述。然后将秘密“告诉”非 root 用户,以便在初始化期间读入。

      (或者,也可以使用 Hashicorp 的 Vault,并通过 HVAC python 模块访问存储在 Vault 中的秘密。)

      一旦告诉这个非 root 用户,这样的事情就很容易了:

      # Remember that './secret_key.txt' is encrypted until it's needed, and only read by a non-root user
      with open('./secret_key.txt') as f:
          SECRET_KEY = f.read().strip() 
      

      这并不完美,而且,是的,攻击者可以枚举变量并访问它——但在运行时这样做非常困难,而 Django 在保护其密钥免受此类威胁向量方面做得很好.

      这比在环境中存储机密要安全得多。

      【讨论】:

      • 谢谢!几天来,我一直试图弄清楚如何隐藏 SECRET_KEY,但每个人都直接跳到“环境变量”解决方案而不质疑它。这篇文章是我第一次承认将秘密放入任何进程都可以访问它的环境中的明显危险。我以为我要疯了。
      【解决方案7】:

      添加到zack-plauch的答案, 获取.env文件的路径,在使用python-dotenvmodule时,可以使用find_dotenv方法,

      from dotenv import load_dotenv, find_dotenv
      
      load_dotenv(find_dotenv())
      
      SECRET_KEY = os.environ['SECRET_KEY']
      

      find_dotenv() 在路径中查找“.env”文件,因此也可以将其保存在同一目录中,

      此外,如果 .env 文件使用名称,例如“django-config.env”,load_dotenv(find_dotenv("django-config.env") 将获取并将其加载到主机环境变量映射。

      【讨论】:

      • 我将此添加到主要答案中?谢谢!
      【解决方案8】:

      我很惊讶没有人谈论django-environ。 我通常会像这样创建一个.env 文件:

      SECRET_KEY=blabla
      OTHER_SECRET=blabla
      

      这个文件应该添加到.gitignore

      您可以在 git 中签入一个名为 .env.example 的示例文件,以便其他人知道他们需要哪个 env var。 .env.example 文件的内容将如下所示(只是没有任何值的键)

      SECRET_KEY=
      OTHER_SECRETS=
      

      【讨论】:

        【解决方案9】:

        在哪里存储SECRET_KEYDJANGO

        将您的 django SECRET_KEY 存储在环境变量或单独的文件中,而不是直接在您的配置模块 settings.py 中编码

        settings.py

        #from an environment variable
        import os
        
        SECRET_KEY = os.environ.get('SECRET_KEY')
        
        #from an file
        with open('/etc/secret_key.txt') as f:
            SECRET_KEY = f.read().strip()
        
        

        如何手动生成Django SECRET_KEY

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

        7^t+3on^bca+t7@)w%2pedaf0m&amp;$_gnne#^s4zk3a%4uu5ly86

        import string
        import secrets
        
        c = string.ascii_letters + string.digits + string.punctuation
        
        secret_key = ''.join(secrets.choice(c) for i in range(67))
        
        print(secret_key) 
        
        

        df&amp;)ok{ZL^6Up$\y2*"&gt;LqHx:D,_f_of#P,~}n&amp;\zs*:y{OTU4CueQNrMz1UH*mhocD

        确保生产中使用的密钥没有在其他地方使用,并避免将其发送到源代码控制。

        【讨论】:

          【解决方案10】:

          django 调试输出将暴露存储在环境变量中的密码。

          【讨论】:

          • 我知道这被否决了,因为它不是一个答案,但是,它确实提出了一个非常好的关于安全的观点,任何来这里的人都应该注意。
          • 不,通常我们不会透露我们的 .env 文件,这就是我们在 gitignore 中添加“.env”的原因
          猜你喜欢
          • 2011-04-30
          • 1970-01-01
          • 1970-01-01
          • 2012-09-06
          • 2019-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多