如何加固生产型 Django 项目的安全性

作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。

介绍

开发一个 Django应用程序可以是一个方便的体验,因为它是灵活和可扩展的结构。这个前提延伸到Django的安全导向设置,可以帮助你准备你的项目生产。

将设置分开,将允许您根据环境设置不同的配置。利用 `.env 来设置环境变量或隐藏机密设置,将确保您不会发布任何可能损害项目的细节。

虽然实施这些策略可能一开始看起来很耗时,但开发一个实用的工作流程将使您能够部署项目的版本,而不会损害安全性或生产力。

在本教程中,您将利用以安全为导向的工作流程为您的Django项目,通过实施和配置基于环境的设置, .env和Django的内置安全设置。

前提条件

在您开始本指南之前,您将需要以下内容:

如果你还没有一个设置,你可以使用我们的 如何安装Django和设置开发环境设置教程。 在该教程中,你将使用这个教程的测试站项目作为一个例子。

<$>[注] :如果您正在使用现有的Django项目,您可能有不同的要求.本教程建议一个特定的项目结构;然而,您也可以根据需要单独使用本教程的每个部分。

步骤 1 – 重组 Django 的设置

在进入Django项目的安全性之前,您需要进入项目目录并激活您的虚拟环境:

1cd django-apps
2. env/bin/activate

在这个第一步中,您将开始将您的settings.py文件重组为环境特定的配置,这是当您需要在不同的环境之间移动项目时的一个很好的做法,例如,开发和生产。

在项目子目录中创建一个名为设置的新目录:

1mkdir testsite/testsite/settings

(根据前提,本教程使用测试站点,但您可以在这里替换您的项目名称。

此目录将取代您当前的 settings.py 配置文件;您的所有基于环境的设置都将存在于此文件夹中的单独文件中。

在新的设置文件夹中,创建三个Python文件:

1cd testsite/testsite/settings
2touch base.py development.py production.py

development.py文件将包含您通常在开发过程中使用的设置,而production.py文件将包含用于生产服务器的设置,您应该将这些设置保留在单独,因为生产配置将使用在开发环境中不起作用的设置;例如,强制使用HTTPS,添加标题和使用生产数据库。

base.py设置文件将包含由 development.pyproduction.py 继承的设置,以减少冗余,并帮助您保持代码清洁。

在您的设置目录中,重命名settings.pybase.py使用以下命令:

1mv ../settings.py base.py

您刚刚完成了新的基于环境的设置目录的概述,您的项目尚未理解您的新配置,因此下一步,您将修复此问题。

步骤 2 — 使用‘django-environ’

目前,Django 不会识别你的新设置目录或其内部文件,因此,在继续使用基于环境的设置之前,你需要让Django 使用‘django-environ’。

转到项目的根目录,然后使用ls命令列出目录的内容:

1cd ../../
2ls

您的项目根目录中的文件应该是这样的:

1[secondary_label Output]
2db.sqlite3 manage.py testsite

安裝 django-environ:

1pip install django-environ

现在你需要配置Django以使用.env。你将编辑两个文件来做到这一点:用于开发的manage.py和用于生产的wsgi.py

首先,打开manage.py以使用nano或您喜爱的文本编辑器进行编辑:

1nano manage.py

添加以下突出的代码:

 1[label testsite/manage.py]
 2import os
 3import sys
 4import environ
 5
 6environ.Env.read_env()
 7
 8def main():
 9    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testsite.settings')
10
11    try:
12        from django.core.management import execute_from_command_line
13    except ImportError as exc:
14        raise ImportError(
15            "Couldn't import Django. Are you sure it's installed and "
16            "available on your PYTHONPATH environment variable? Did you "
17            "forget to activate a virtual environment?"
18        ) from exc
19    execute_from_command_line(sys.argv)
20
21if __name__ == '__main__':
22    main()

保存并关闭manage.py,按CTRL+X,按Y来保存,然后按ENTER

接下来打开wsgi.py来编辑:

1nano testsite/wsgi.py

添加以下突出的线条:

 1[label testsite/testsite/wsgi.py]
 2
 3import os
 4import environ
 5
 6environ.Env.read_env()
 7
 8from django.core.wsgi import get_wsgi_application
 9
10os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testsite.settings')
11
12application = get_wsgi_application()

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

您添加到这两个文件的代码可以做两件事:首先,每当 Django 运行时—‘manage.py’ 用于运行开发,‘wsgi.py’ 用于生产 — 你会告诉它寻找你的.env 文件。

最后,您将在当前目录中创建一个 .env:

1nano .env

现在添加下列行来设置环境发展:

1[label testsite/.env]
2DJANGO_SETTINGS_MODULE="testsite.settings.development"

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

<$>[注] **注:**添加 .env 到您的 .gitignore 文件,所以它永远不会包含在您的承诺中;您将使用此文件包含您不希望公开可见的密码和 API 密钥等数据。

建议在您的项目中创建一个.env.example,这样您可以随时随地轻松创建一个新的.env

因此,默认情况下,Django 将使用testsite.settings.development,但如果您将DJANGO_SETTINGS_MODULE更改为testsite.settings.production,它将开始使用您的生产配置。

步骤 3 – 创建开发和生产设置

接下来,您将打开您的base.py并在单独的development.pyproduction.py文件中添加您希望对每个环境进行修改的配置。

<$>[注] 注: 根据环境,您可以根据环境来确定需要配置的设置。本教程只将涵盖生产和开发设置的一个常见例子(即安全设置和单独的数据库配置)。

在本教程中,你将使用 Django 项目从 前提教程作为示例项目. 你将设置从 base.py 移动到 development.py. 开始打开 development.py:

1nano testsite/settings/development.py

然后添加以下代码:

 1[label testsite/testsite/settings/development.py]
 2import os
 3from .base import *
 4
 5DEBUG = True
 6
 7DATABASES = {
 8    'default': {
 9        'ENGINE': 'django.db.backends.sqlite3',
10        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
11    }
12}

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

首先,您将从「base.py」导入 - 此文件继承了从「base.py」的设置. 然后,您将转移您想要对开发环境进行修改的设置. 在这种情况下,开发的特定设置如下:「DEBUG」,您需要在开发中是「True」,但不是在生产中;以及「DATABASES」,本地数据库而不是生产数据库。

<$>[注] ** 注意:** 出于安全目的,Django 的 DEBUG 输出不会显示任何可能包含字符串API,KEY,PASS,SECRET,SIGNATURETOKEN的设置。

这样做是为了确保秘密不会被揭露,如果您意外地部署一个项目进入生产,但DEBUG仍然启用。

尽管如此,永远不要在启用DEBUG时公开部署项目,这只会危及您的项目的安全性。

接下来,你会添加到 production.py. 用以下命令打开文件:

1nano testsite/settings/production.py

然后添加以下代码. 生产将类似于 development.py,但具有不同的数据库配置和 DEBUG 设置为 False:

 1[label testsite/testsite/settings/production.py]
 2import os
 3from .base import *
 4import environ
 5
 6env = environ.Env()
 7environ.Env.read_env()
 8
 9DEBUG = False
10
11ALLOWED_HOSTS = []
12
13DATABASES = {
14    'default': {
15        'ENGINE': env('SQL_ENGINE', default='django.db.backends.sqlite3'),
16        'NAME': env('SQL_DATABASE', default=os.path.join(BASE_DIR, 'db.sqlite3')),
17        'USER': env('SQL_USER', default='user'),
18        'PASSWORD': env('SQL_PASSWORD', default='password'),
19        'HOST': env('SQL_HOST', default='localhost'),
20        'PORT': env('SQL_PORT', default=''),
21    }
22}

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

对于所提供的示例数据库配置,您可以使用 .env 来配置每个所提供的凭据,包括默认设置。

根据您所使用的示例设置,当您将项目设置为使用生产设置时,DEBUG 将变为,ALLOWED_HOSTS被定义,您将开始使用您(已经)在服务器上配置的不同的数据库。

步骤 4 — 使用 Django 的安全设置

Django 包含安全设置,可供您添加到您的项目中。在此步骤中,您将为您的项目添加安全设置,这些设置被认为是任何生产项目所必需的。

在大多数情况下,这些设置将强制使用HTTPS用于各种Web功能,例如(https://en.wikipedia.org/wiki/HTTP_cookie#:~:text=A%20session%20cookie%2C%20also%20known,the%20user%20closes%20the%20browser.),CSRF Cookie,升级HTTP到HTTPS等。

首先打开production.py:

1nano testsite/settings/production.py

在您的文件中,根据以下代码的解释,添加对您的项目工作的突出设置:

 1[label testsite/testsite/settings/production.py]
 2import os
 3from .base import *
 4import environ
 5
 6env = environ.Env()
 7environ.Env.read_env()
 8
 9DEBUG = False
10
11ALLOWED_HOSTS = ['your_domain', 'www.your_domain']
12
13DATABASES = {
14    'default': {
15        'ENGINE': env('SQL_ENGINE', default='django.db.backends.sqlite3'),
16        'NAME': env('SQL_DATABASE', default=os.path.join(BASE_DIR, 'db.sqlite3')),
17        'USER': env('SQL_USER', default='user'),
18        'PASSWORD': env('SQL_PASSWORD', default='password'),
19        'HOST': env('SQL_HOST', default='localhost'),
20        'PORT': env('SQL_PORT', default=''),
21    }
22}
23
24SECURE_SSL_REDIRECT = True
25
26SESSION_COOKIE_SECURE = True
27
28CSRF_COOKIE_SECURE = True
29
30SECURE_BROWSER_XSS_FILTER = True

ALLOWED_HOSTS'是代表您项目所能服务的主机/域名的字符串列表。 这是防止攻击者给缓存和DNS下毒的安全措施. 在[Django文件](https://docs.djangoproject.com/en/4.1/ref/settings/)中查找关于ALLOWED-HOSTS'的更多详情。 (- ) SECURE_SSL_REDIRECT' 将所有 HTTP 请求重定向到 HTTPS (除非豁免) 。 这意味着您的工程将永远尝试使用加密连接. 您需要将 SSL 配置在您的服务器上才能工作 。 请注意, 如果您已经配置了 Nginx 或 Apache 来完成此任务, 此设置将会是冗余的 。 (_) ( )* 'SESSION_COOKIE_SECURE'告诉浏览器,饼干只能通过HTTPS处理. 这意味着您为活动制作的 cookie, 如登录, 只会在加密连接上工作 。 ( _) ( )* CSRF-COOKIE-SECURE'与SESSION-COOKIE-SECURE'相同,但适用于你的CSRF标志。 _CSRF令牌_防止[跨站请求伪造] (https://en.wikipedia.org/wiki/Cross-site_request_forgery). Django CSRF的保护通过确保向您的项目提交(登入、注册等)的任何表格都是由您的项目创建的,而不是第三方的。 (_) ( )* SECURE_BROWSERXSS-FILTER'将`XSS-保护: 1;模式=块'标题放在所有尚未获得的回复上。 这将确保第三方不能向您的项目注入脚本 。 例如,如果用户使用公共字段在数据库中存储脚本,当该脚本被检索并显示给其他用户时,它不会运行. ( (英语)

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

如果您想了解更多关于 Django 中可用的不同安全设置,请参阅他们的 文档

<$>[警告] 警告: Django 的文档指出,您不应该完全依赖 SECURE_BROWSER_XSS_FILTER

附加设置

以下设置支持 HTTP 严格运输安全(HSTS),这意味着您的整个网站必须随时使用 SSL。

  • SECURE_HSTS-SECONDS'是设定的几秒钟时间。 如果您设置这个小时( 以秒计) , 每次访问您网站上的网页, 它会告诉您的浏览器, 在接下来的一小时里, HTTPS 是您访问该网站的唯一方式 。 如果您在那个时间访问您网站的不安全部分, 浏览器会显示错误, 不安全的页面将无法访问 。 ( _) ( )* SECURE_HSTS-PRELOAD'只有在设定SECURE_HSTS-SECONDS'的情况下才有效。 此页眉指示浏览器要 [预装] (https://hstspreload.org/] 您的网站 。 这意味着您的网站会被添加到一个硬码列表中,该列表在受欢迎的浏览器中被执行,比如Firefox和Chrome. 这需要您的网站总是加密的 。 注意这个标题很重要。 如果您在任何时间决定不为您的项目使用加密,则需要几周的时间才能从 [HSTS preload list] (https://hstspreload.org/). (_). ( )* SECURE_HSTS_INCLUDE_SUBDOMAINS'对所有子域应用HSTS头. 启用此标题意味着 您的域 不安全的域 都需要加密, 即使 不安全的域。 您的域 与 Django 项目无关 。 ( _) (英语)

<$>[警告] **警告:**错误配置这些额外设置可能会在相当长的时间内破坏您的网站。

请在实施这些设置之前阅读 Django 关于 HSTS 的文档

需要考虑这些设置将如何与你自己的Django项目合作;总的来说,这里讨论的配置是大多数Django项目的良好基础。

步骤 5 — 使用django-environ为秘密

本教程的最后部分将帮助您利用django-environ。这将允许您隐藏某些信息,例如您的项目的SECRET_KEY(https://docs.djangoproject.com/en/4.1/ref/settings/#std:setting-SECRET_KEY)或管理员的登录 URL。如果您打算在GitHub或GitLab等平台上发布代码,这是一个很好的想法,因为这些秘密不会被发布。相反,每次您在本地环境或服务器上最初设置您的项目,您可以创建一个新的.env文件并定义这些秘密变量。

您必须隐藏您的SECRET_KEY,以便在本节中开始工作。

在您的项目的 root 目录中打开您的 .env 文件:

1nano .env

并添加以下行,确保用自己的秘密字符串代替your_secret_key:

1[label testsite/.env]
2DJANGO_SETTINGS_MODULE="testsite.settings.development"
3SECRET_KEY="your_secret_key"

然后通过按CTRL+X来保存和关闭文件,按Y来保存,然后按ENTER

接下来,打开base.py:

1nano testsite/settings/base.py

更新SECRET_KEY变量如下:

1[label testsite/testsite/settings/base.py]
2. . .
3import environ
4
5env = environ.Env()
6environ.Env.read_env()
7
8SECRET_KEY = env('SECRET_KEY')
9. . .

<$>[注] 注:SECRET_KEY不应该被实际的秘密密密钥取代。

然后通过按CTRL+X来保存和关闭文件,按Y来保存,然后按ENTER

最后,你会通过添加一个长串随机字符来隐藏你的管理 URL,所以而不是去到your_domain/admin,你会去到your_domain/very_secret_url/admin

再次打开.env:

1nano .env

然后添加一个SECRET_ADMIN_URL变量:

1[label testsite/.env]
2DJANGO_SETTINGS_MODULE="testsite.settings.development"
3SECRET_KEY="your_secret_key"
4SECRET_ADMIN_URL="very_secret_url"

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

现在你会告诉Django用SECRET_ADMIN_URL隐藏你的管理 URL:

1nano testsite/urls.py

<$>[注] 注: 不要忘了用自己的秘密URL代替very_secret_url

如果你想为这个变量使用随机字符串,Python 提供了一个很棒的 secrets.py 库来生成此类字符串。

编辑 admin URL 如下:

 1[label testsite/testsite/urls.py]
 2from django.contrib import admin
 3from django.urls import path
 4import environ
 5
 6env = environ.Env()
 7environ.Env.read_env()
 8
 9urlpatterns = [
10    path(env('SECRET_ADMIN_URL') + '/admin/', admin.site.urls),
11]

保存和关闭文件,按CTRL+X,按Y来保存,然后按ENTER

您现在可以找到管理员登录页面在 /very_secret_url/admin/ 而不是仅仅是 /admin/:

Admin login page

结论

在本教程中,您已经配置了当前的Django项目以便在不同的环境中轻松使用。您的项目现在利用django-environ来处理秘密和设置。

如果您已按指示启用了所有推荐的安全组件和重新部署设置,则您的项目具有以下关键功能:

  • SSL/HTTPS 用于所有通信(例如子域、cookie、CSRF)。
  • XSS(跨网站脚本)攻击预防
  • CSRF(跨网站请求伪造)攻击预防 *隐藏的项目秘密密密钥 *隐藏的管理员登录 URL,防止暴力攻击 *开发和生产的独立设置

如果您有兴趣了解更多关于Django的信息,请查看我们关于Django开发的教程系列(https://www.digitalocean.com/community/tutorial_series/django-development)。

此外,如果你还没有把你的项目投入生产,这里是关于如何在Ubuntu 20.04上设置Django使用Postgres,Nginx和Gunicorn的教程(https://andsky.com/tech/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-20-04)。

当然,请阅读 Django 的 设置文档,以获取更多信息。

Published At
Categories with 技术
comments powered by Disqus