Django 中的安全

本文档概述了 Django 的安全功能。它包括有关保护 Django 驱动网站的安全性的建议。

跨站脚本 (XSS) 防护

XSS 攻击允许用户将客户端脚本注入其他用户的浏览器。这通常是通过将恶意脚本存储在数据库中来实现的,恶意脚本将在数据库中被检索并显示给其他用户,或者通过让用户点击链接来执行,该链接将导致攻击者的 JavaScript 被用户的浏览器执行。但是,只要数据在包含在页面之前没有被充分清理,XSS 攻击可能源于任何不受信任的数据源,例如 Cookie 或 Web 服务。

使用 Django 模板可以保护您免受大多数 XSS 攻击。但是,了解它提供的保护及其局限性非常重要。

Django 模板转义特定字符,这些字符对 HTML 尤其危险。虽然这可以保护用户免受大多数恶意输入的影响,但它并非完全万无一失。例如,它不会保护以下内容

<style class={{ var }}>...</style>

如果var设置为'class1 onmouseover=javascript:func()',这可能会导致未经授权的 JavaScript 执行,具体取决于浏览器如何呈现不完美的 HTML。(引用属性值可以解决这种情况。)

在使用is_safe和自定义模板标签、safe模板标签、mark_safe以及自动转义关闭时,也需要注意。

此外,如果您使用模板系统输出 HTML 以外的内容,则可能需要转义完全不同的字符和单词。

在将 HTML 存储在数据库中时,也应该非常小心,尤其是在检索和显示该 HTML 时。

跨站请求伪造 (CSRF) 防护

CSRF 攻击允许恶意用户在不知情或未经同意的情况下使用其他用户的凭据执行操作。

Django 具有针对大多数 CSRF 攻击类型的内置保护,前提是您已启用并使用它(在适当的地方)。但是,与任何缓解技术一样,它也存在局限性。例如,可以全局或针对特定视图禁用 CSRF 模块。您只有在了解自己在做什么的情况下才能这样做。如果您的网站具有您无法控制的子域,则还有一些局限性

CSRF 保护的工作方式是检查每个 POST 请求中的密钥。这确保恶意用户无法“重放”表单 POST 到您的网站,并让另一个登录用户无意中提交该表单。恶意用户必须知道该密钥,该密钥是特定于用户的(使用 Cookie)。

当与HTTPS一起部署时,CsrfViewMiddleware将检查 HTTP referer 标头是否设置为相同来源(包括子域和端口)上的 URL。由于 HTTPS 提供额外的安全性,因此必须确保连接使用 HTTPS(在可用时),方法是转发不安全的连接请求并对受支持的浏览器使用 HSTS。

除非绝对必要,否则请务必小心使用csrf_exempt装饰器标记视图。

SQL 注入防护

SQL 注入是一种攻击类型,攻击者能够在数据库上执行任意 SQL 代码。这可能导致记录被删除或数据泄露。

Django 的查询集受到 SQL 注入的保护,因为它们的查询是使用查询参数化构建的。查询的 SQL 代码与查询的参数分开定义。由于参数可能是用户提供的,因此是不安全的,它们会被底层数据库驱动程序转义。

Django 还允许开发人员编写原始查询或执行自定义 SQL。这些功能应该谨慎使用,并且您应该始终小心正确转义用户可以控制的任何参数。此外,在使用extra()RawSQL时,应谨慎操作。

点击劫持防护

点击劫持是一种攻击类型,恶意网站将另一个网站包装在框架中。此攻击可能导致毫无戒心的用户被诱骗在目标网站上执行意外操作。

Django 包含点击劫持保护,形式为X-Frame-Options 中间件,它可以在支持的浏览器中防止网站在框架内呈现。可以在每个视图的基础上禁用保护,或配置发送的确切标头值。

对于任何不需要第三方网站将其页面包装在框架中的网站,或者只需要允许网站的一小部分这样做的网站,强烈建议使用此中间件。

SSL/HTTPS

出于安全考虑,最好在 HTTPS 后面部署您的网站。如果没有,恶意网络用户可能会嗅探身份验证凭据或客户端和服务器之间传输的任何其他信息,在某些情况下,**主动**网络攻击者可能会更改双向发送的数据。

如果您想要 HTTPS 提供的保护,并且已在服务器上启用它,则可能需要执行一些其他步骤

  • 如有必要,请设置SECURE_PROXY_SSL_HEADER,确保您已彻底了解那里的警告。未能执行此操作会导致 CSRF 漏洞,并且执行不正确也会很危险!

  • SECURE_SSL_REDIRECT设置为True,以便将 HTTP 请求重定向到 HTTPS。

    请注意SECURE_PROXY_SSL_HEADER下的警告。对于反向代理的情况,配置主 Web 服务器来执行重定向到 HTTPS 可能更容易或更安全。

  • 使用“安全”Cookie。

    如果浏览器最初通过 HTTP 连接(这是大多数浏览器的默认设置),则可能泄露现有 Cookie。为此,您应该将SESSION_COOKIE_SECURECSRF_COOKIE_SECURE设置为True。这指示浏览器仅通过 HTTPS 连接发送这些 Cookie。请注意,这意味着会话将无法通过 HTTP 工作,并且 CSRF 保护将阻止接受通过 HTTP 的任何 POST 数据(如果您将所有 HTTP 流量重定向到 HTTPS,则这将很好)。

  • 使用HTTP 严格传输安全 (HSTS)

    HSTS 是一个 HTTP 标头,它通知浏览器所有对特定站点的未来连接都应始终使用 HTTPS。结合将 HTTP 请求重定向到 HTTPS,这将确保连接始终享有 SSL 提供的额外安全性,前提是已成功建立一个连接。可以使用SECURE_HSTS_SECONDSSECURE_HSTS_INCLUDE_SUBDOMAINSSECURE_HSTS_PRELOAD或在 Web 服务器上配置 HSTS。

主机标头验证

Django 在某些情况下使用客户端提供的Host标头来构建 URL。虽然这些值经过清理以防止跨站脚本攻击,但伪造的Host值可用于跨站请求伪造、缓存中毒攻击以及中毒电子邮件中的链接。

因为即使看似安全的 Web 服务器配置也容易受到伪造的Host标头的影响,所以 Django 会根据ALLOWED_HOSTS设置在django.http.HttpRequest.get_host()方法中验证Host标头。

此验证仅通过get_host()应用;如果您的代码直接从request.META访问Host标头,则会绕过此安全保护。

有关更多详细信息,请参阅完整的ALLOWED_HOSTS文档。

警告

之前的文档版本建议您配置 Web 服务器以确保其验证传入的 HTTP Host 头部。虽然仍然建议这样做,但在许多常见的 Web 服务器中,看似验证 Host 头部的配置实际上可能并未执行此操作。例如,即使 Apache 已配置为从具有 ServerName 设置的非默认虚拟主机提供您的 Django 站点服务,HTTP 请求仍然可能匹配此虚拟主机并提供伪造的 Host 头部。因此,Django 现在要求您显式设置 ALLOWED_HOSTS,而不是依赖于 Web 服务器配置。

此外,如果您的配置需要,Django 还要求您显式启用对 X-Forwarded-Host 头部的支持(通过 USE_X_FORWARDED_HOST 设置)。

Referrer 策略

浏览器使用 Referer 头部来向站点发送有关用户如何到达该站点的的信息。通过设置 *Referrer 策略*,您可以帮助保护用户的隐私,限制在哪些情况下设置 Referer 头部。有关详细信息,请参阅 安全中间件参考中的 Referrer 策略部分

跨源打开程序策略

跨源打开程序策略 (COOP) 头部允许浏览器通过将顶级窗口置于不同的上下文组中来隔离顶级窗口与其他文档,从而使其无法直接与顶级窗口交互。如果受 COOP 保护的文档打开跨源弹出窗口,则弹出窗口的 window.opener 属性将为 null。COOP 可防止跨源攻击。有关详细信息,请参阅 安全中间件参考中的跨源打开程序策略部分

会话安全性

类似于 CSRF 限制 要求站点部署方式应确保不受信任的用户无权访问任何子域,django.contrib.sessions 也存在一些限制。有关详细信息,请参阅 会话主题指南中的安全性部分

用户上传的内容

注意

请考虑 从云服务或 CDN 提供静态文件 以避免其中一些问题。

  • 如果您的站点接受文件上传,强烈建议您在 Web 服务器配置中将这些上传限制为合理的大小,以防止拒绝服务 (DOS) 攻击。在 Apache 中,可以使用 LimitRequestBody 指令轻松设置此项。

  • 如果您正在提供您自己的静态文件,请确保已禁用诸如 Apache 的 mod_php 之类的处理程序,这些处理程序会将静态文件作为代码执行。您不希望用户能够通过上传和请求特制文件来执行任意代码。

  • 当以不遵循安全最佳实践的方式提供媒体时,Django 的媒体上传处理会带来一些漏洞。具体来说,如果文件包含有效的 PNG 头部后跟恶意 HTML,则可以将 HTML 文件上传为图像。此文件将通过 Django 用于 ImageField 图像处理的库 (Pillow) 的验证。此文件随后显示给用户时,根据 Web 服务器的类型和配置,它可能会显示为 HTML。

    在框架级别,不存在能够安全验证所有用户上传文件内容的万无一失的技术解决方案,但是,您可以采取一些其他步骤来减轻这些攻击的影响。

    1. 可以通过始终从不同的顶级或二级域提供用户上传的内容来防止一类攻击。这可以防止 同源策略 保护(例如跨站点脚本)阻止的任何漏洞。例如,如果您的站点运行在 example.com 上,则您需要从类似 usercontent-example.com 的地址提供上传的内容(MEDIA_URL 设置)。从类似 usercontent.example.com 的子域提供内容 *不足以* 解决问题。

    2. 除此之外,应用程序可以选择定义用户上传文件的允许文件扩展名列表,并配置 Web 服务器以仅提供此类文件。

其他安全主题

虽然 Django 默认提供了良好的安全保护,但正确部署应用程序并利用 Web 服务器、操作系统和其他组件的安全保护仍然很重要。

  • 确保您的 Python 代码位于 Web 服务器根目录之外。这将确保您的 Python 代码不会意外地作为纯文本提供服务(或意外执行)。

  • 注意任何 用户上传的文件

  • Django 不会限制对用户的身份验证请求。为了防止针对身份验证系统的暴力破解攻击,您可以考虑部署 Django 插件或 Web 服务器模块来限制这些请求。

  • 保持您的 SECRET_KEY 和(如果正在使用)SECRET_KEY_FALLBACKS 保密。

  • 最好使用防火墙限制缓存系统和数据库的可访问性。

  • 查看开放 Web 应用程序安全项目 (OWASP) 的 十大列表,其中列出了 Web 应用程序中的一些常见漏洞。虽然 Django 拥有解决某些问题的工具,但其他问题必须在项目设计中加以考虑。

  • Mozilla 讨论了有关 Web 安全性 的各种主题。他们的页面还包含适用于任何系统的安全原则。

返回顶部