Django中的安全性

本文档是Django安全功能的概述。 它包括关于保护一个Django驱动的站点的建议。

跨站点脚本(XSS)保护

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

使用Django模板可以防止大多数XSS攻击。 但是,了解它提供的保护和限制是非常重要的。

Django模板escape specific characters 虽然这可以保护用户免受大多数恶意输入,但并不完全是万无一失的。 例如,它不会保护以下内容:

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

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

在自定义模板标签,safe模板标签,mark_safe以及autoescape关闭时使用is_safe

另外,如果您使用模板系统输出非HTML的内容,则可能会有完全分离的字符和需要转义的单词。

在数据库中存储HTML时,也应该非常小心,特别是在检索并显示HTML时。

跨站请求伪造(CSRF)保护

CSRF攻击允许恶意用户在没有该用户的知识或同意的情况下使用另一用户的凭证执行操作。

Django已经内置了对大多数类型的CSRF攻击的保护,只要你有适当的enabled and used it 但是,与任何缓解技术一样,也存在限制。 例如,可以在全局或特定视图中禁用CSRF模块。 如果你知道你在做什么,你应该只做这个。 如果您的网站拥有不受您控制的子域名,则还有其他limitations

CSRF protection works by checking for a secret in each POST request. 这确保了恶意用户不能简单地“重放”表单POST到您的网站,并有另一个登录用户无意中提交该表单。 恶意用户必须知道秘密,这是用户特定的(使用cookie)。

当使用HTTPS进行部署时,CsrfViewMiddleware将检查HTTP referer头是否设置为同一个源(包括子域和端口)上的URL。 由于HTTPS提供了额外的安全性,因此必须通过转发不安全的连接请求并将HSTS用于支持的浏览器,确保连接使用HTTPS。

使用csrf_exempt修饰器标记视图时要非常小心,除非绝对必要。

SQL注入保护

SQL注入是一种恶意用户能够在数据库上执行任意SQL代码的攻击类型。 这可能会导致记录被删除或数据泄漏。

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

Django还为开发人员提供了编写raw queries或执行custom sql的能力。 应该谨慎使用这些功能,您应该小心妥善地转义用户可以控制的任何参数。 另外,使用extra()RawSQL时应该谨慎。

点击劫持保护

点击劫持是一种恶意站点在框架中包装另一个站点的攻击类型。 这种攻击可能会导致不知情的用户被欺骗,从而在目标站点上执行意外操作。

Django contains clickjacking protection in the form of the X-Frame-Options middleware which in a supporting browser can prevent a site from being rendered inside a frame. 可以禁用每个视图的保护或配置发送的确切报头值。

强烈建议中间件用于任何不需要第三方站点将其页面包装在一个框架中的站点,或者只需要允许该站点的一小部分。

SSL / HTTPS ¶ T0>

在HTTPS后部署网站安全性总是更好。 Without this, it is possible for malicious network users to sniff authentication credentials or any other information transferred between client and server, and in some cases – active network attackers – to alter data that is sent in either direction.

如果您想要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 Strict Transport Security(HSTS)

    HSTS是一个HTTP标头,通知浏览器所有未来连接到特定的站点应该总是使用HTTPS。 结合通过HTTP将请求重定向到HTTPS,这将确保连接始终享有SSL提供的附加安全性,只要发生了一次成功的连接。 HSTS may either be configured with SECURE_HSTS_SECONDS, SECURE_HSTS_INCLUDE_SUBDOMAINS, and SECURE_HSTS_PRELOAD, or on the Web server.

主机头验证

在某些情况下,Django使用客户端提供的Host头来构造URL。 尽管这些值已经过清理以防止跨站点脚本攻击,但是可以使用假的Host值进行跨站点请求伪造,缓存中毒攻击以及邮件中的中毒链接。

Because even seemingly-secure web server configurations are susceptible to fake Host headers, Django validates Host headers against the ALLOWED_HOSTS setting in the django.http.HttpRequest.get_host() method.

This validation only applies via get_host(); if your code accesses the Host header directly from request.META you are bypassing this security protection.

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

警告

此文档的以前版本建议配置您的Web服务器以确保它验证传入的HTTP Host标头。 尽管仍然建议这样做,但在许多常见的Web服务器中,似乎验证Host标头的配置实际上可能不这样做。 例如,即使Apache被配置为使得您的Django站点由设置了ServerName的非默认虚拟主机提供服务,但HTTP请求仍可能与此虚拟主机匹配并提供假Host标题。 因此,Django现在需要明确地设置ALLOWED_HOSTS,而不是依靠Web服务器配置。

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

会话安全性

CSRF limitations类似,要求部署站点以使不可信用户无权访问任何子域,django.contrib.sessions也具有限制。 有关详细信息,请参阅the session topic guide section on security

用户上传的内容

注意

Consider serving static files from a cloud service or CDN to avoid some of these issues.

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

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

  • 当媒体以不遵循安全最佳实践的方式提供时,Django的媒体上传处理会造成一些漏洞。 具体来说,如果HTML文件包含有效的PNG头,然后是恶意HTML,则可以将HTML文件作为图像上传。 This file will pass verification of the library that Django uses for ImageField image processing (Pillow). 当此文件随后显示给用户时,可能会显示为HTML,具体取决于您的Web服务器的类型和配置。

    框架级别没有防弹技术解决方案来安全地验证所有用户上传的文件内容,但是,您可以采取一些其他步骤来减轻这些攻击:

    1. 通过始终提供来自不同顶级或二级域的用户上传内容,可以防止一类攻击。 这可以防止由同源策略保护(如跨站点脚本)阻止的任何利用。 For example, if your site runs on example.com, you would want to serve uploaded content (the MEDIA_URL setting) from something like usercontent-example.com. It’s not sufficient to serve content from a subdomain like usercontent.example.com.
    2. 除此之外,应用程序可以选择为用户上传的文件定义允许的文件扩展名白名单,并将Web服务器配置为仅提供这些文件。

其他安全主题

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

  • 确保你的Python代码不在Web服务器的根目录下。 这将确保您的Python代码不会意外地作为纯文本(或意外执行)提供。
  • 请注意任何user uploaded files
  • Django不会限制对用户进行身份验证的请求。 为了防止对身份验证系统的暴力攻击,您可以考虑部署一个Django插件或Web服务器模块来限制这些请求。
  • Keep your SECRET_KEY a secret.
  • 使用防火墙限制缓存系统和数据库的可访问性是个好主意。
  • 查看开放Web应用程序安全项目(OWASP)前10名列表,其中列出了Web应用程序中的一些常见漏洞。 尽管Django有一些工具可以解决一些问题,但在设计项目时必须考虑其他问题。