跳到内容

Django 安全备忘录

简介

Django 框架是一个强大的 Python Web 框架,它内置了开箱即用的安全功能,可以防止常见的 Web 漏洞。本备忘录列出了开发人员可以采取的措施和安全提示,以开发安全的 Django 应用程序。它旨在涵盖常见的漏洞,以提高 Django 应用程序的安全态势。每个条目都有简要解释和特定于 Django 环境的相关代码示例。

Django 框架提供了一些内置的安全功能,旨在默认安全。这些功能也具有灵活性,使开发人员能够重用组件以应对复杂的用例。这导致了不熟悉组件内部工作原理的开发人员可能以不安全的方式配置它们的情况。本备忘录旨在列举一些此类用例。

一般建议

  • 始终保持 Django 和应用程序的依赖项最新,以跟上安全漏洞。
  • 确保应用程序在生产环境中绝不处于 DEBUG 模式。切勿在生产环境中运行 DEBUG = True
  • 使用诸如 django_ratelimitdjango-axes 等包来防止暴力破解攻击。

认证

  • 使用 django.contrib.auth 应用程序的视图和表单进行用户认证操作,例如登录、注销、密码更改等。在 settings.py 文件中的 INSTALLED_APPS 设置中包含此模块及其依赖项 django.contrib.contenttypesdjango.contrib.sessions
INSTALLED_APPS = [
    # ...
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    # ...
]
  • 使用 @login_required 装饰器确保只有经过认证的用户才能访问视图。下面的示例代码展示了 @login_required 的用法。
from django.contrib.auth.decorators import login_required

# User is redirected to default login page if not authenticated.
@login_required
def my_view(request):
  # Your view logic

# User is redirected to custom '/login-page/' if not authenticated.
@login_required(login_url='/login-page/')
def my_view(request):
  # Your view logic
  • 使用密码验证器强制执行密码策略。在 settings.py 文件中添加或更新 AUTH_PASSWORD_VALIDATORS 设置,以包含应用程序所需的特定验证器。
AUTH_PASSWORD_VALIDATORS = [
  {
    # Checks the similarity between the password and a set of attributes of the user.
    'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    'OPTIONS': {
      'user_attributes': ('username', 'email', 'first_name', 'last_name'),
      'max_similarity': 0.7,
    }
  },
  {
    # Checks whether the password meets a minimum length.
    'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    'OPTIONS': {
      'min_length': 8,
    }
  },
  {
    # Checks whether the password occurs in a list of common passwords
    'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
  },
  {
    # Checks whether the password isn’t entirely numeric
    'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
  }
]
  • 使用 make-password 工具函数存储密码以哈希纯文本密码。
from django.contrib.auth.hashers import make_password
#...
hashed_pwd = make_password('plaintext_password')
  • 通过使用 check-password 工具函数来检查纯文本密码与哈希密码是否匹配。
from django.contrib.auth.hashers import check_password
#...
plain_pwd = 'plaintext_password'
hashed_pwd = 'hashed_password_from_database'

if check_password(plain_pwd, hashed_pwd):
  print("The password is correct.")
else:
  print("The password is incorrect.")

密钥管理

settings.py 中的 SECRET_KEY 参数用于加密签名,应保密。考虑以下建议:

  • 生成至少 50 个或更多字符的密钥,其中包含字母、数字和符号的混合。
  • 确保 SECRET_KEY 是使用强随机生成器生成的,例如 Django 中的 get_random_secret_key() 函数。
  • 避免在 settings.py 或任何其他位置硬编码 SECRET_KEY 值。考虑将键值存储在环境变量或秘密管理器中。
import os
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
  • 定期轮换密钥,请记住此操作可能会使会话、密码重置令牌等失效。如果密钥暴露,请立即轮换。

头部

在项目的 settings.py 文件的 MIDDLEWARE 设置中包含 django.middleware.security.SecurityMiddleware 模块,以向响应添加与安全相关的头部。此模块用于设置以下参数:

  • SECURE_CONTENT_TYPE_NOSNIFF:将此键设置为 True。通过启用 X-Content-Type-Options: nosniff 头部来防止 MIME 类型嗅探攻击。
  • SECURE_HSTS_SECONDS:确保网站只能通过 HTTPS 访问。

在项目的 settings.pyMIDDLEWARE 设置中包含 django.middleware.clickjacking.XFrameOptionsMiddleware 模块(此模块应列在 django.middleware.security.SecurityMiddleware 模块之后,因为顺序很重要)。此模块用于设置以下参数:

  • X_FRAME_OPTIONS:将此键设置为 'DENY' 或 'SAMEORIGIN'。此设置将 X-Frame-Options 头部添加到所有 HTTP 响应中。这可以防止点击劫持攻击。

Cookies

  • SESSION_COOKIE_SECURE:在 settings.py 文件中将此键设置为 True。这将只通过安全 (HTTPS) 连接发送会话 cookie。
  • CSRF_COOKIE_SECURE:在 settings.py 文件中将此键设置为 True。这将确保 CSRF cookie 只通过安全连接发送。
  • 每当您在视图中使用 HttpResponse.set_cookie() 方法设置自定义 cookie 时,请确保将其 secure 参数设置为 True
response = HttpResponse("Some response")
response.set_cookie('my_cookie', 'cookie_value', secure=True)

跨站请求伪造 (CSRF)

  • 在项目的 settings.pyMIDDLEWARE 设置中包含 django.middleware.csrf.CsrfViewMiddleware 模块,以向响应添加与 CSRF 相关的头部。
  • 在表单中使用 {% csrf_token %} 模板标签来包含 CSRF 令牌。示例如下所示。
<form method="post">
    {% csrf_token %}
    <!-- Your form fields here -->
</form>
  • 对于 AJAX 调用,必须在 AJAX 调用中使用之前提取请求的 CSRF 令牌。
  • 更多建议和控制措施可以在 Django 的 跨站请求伪造保护 文档中找到。

跨站脚本 (XSS)

本节中的建议是前面已提及的 XSS 建议的补充。

  • 使用内置模板系统在 Django 中渲染模板。请参阅 Django 的 自动 HTML 转义 文档以了解更多信息。
  • 尽量避免使用 safe 过滤器(或 mark_safe 函数)来禁用 Django 的自动模板转义。如果确实需要使用它,请确保输入来自受信任的来源。处理用户控制的输入时需要格外小心。
  • 在 Django 模板中将数据传递给 JavaScript 时,请使用 json_script 模板过滤器。
  • 请参阅 Django 的 跨站脚本 (XSS) 保护 文档以了解更多信息。

HTTPS

  • 如果尚未添加,请在项目的 settings.pyMIDDLEWARE 设置中包含 django.middleware.security.SecurityMiddleware 模块。
  • settings.py 文件中设置 SECURE_SSL_REDIRECT = True,以确保所有通信都通过 HTTPS。这将自动将任何 HTTP 请求重定向到 HTTPS。这也是一个 301(永久)重定向,因此您的浏览器将记住后续请求的重定向。
  • 如果您的 Django 应用程序位于代理或负载均衡器之后,请设置 SECURE_PROXY_SSL_HEADER,以便 Django 可以检测原始请求的协议。有关详细信息,请参阅 SECURE_PROXY_SSL_HEADER 文档

管理面板 URL

建议修改默认的管理员面板 URL (example.com/admin/),以稍微增加自动化攻击的难度。操作方法如下:

在项目默认的应用程序文件夹中,找到管理顶级 URL 的 urls.py 文件。在该文件中,修改 urlpatterns 变量(一个列表),使指向 admin.site.urls 的 URL 不同于 "admin/"。这种方法通过混淆用于管理访问的常见端点来增加一层额外的安全性。

参考资料

附加文档 -