Django安全

这份文档是 Django 的安全功能的概述。 它包括给 Django 驱动的网站一些加固建议。

跨站脚本 (XSS) 防护

XSS攻击允许用户注入客户端脚本到其他用户的浏览器里。 这通常是通过存储在数据库中的恶意脚本,它将检索并显示给其他用户,或者通过让用户点击一个链接,这将导致攻击者的 JavaScript 被用户的浏览器执行。 然而,XSS 攻击可以来自任何不受信任的源数据,如 Cookie 或 Web 服务,任何没有经过充分处理就包含在网页中的数据。

使用 Django 模板保护你免受多数 XSS 攻击。 然而,重要的是要了解它提供了什么保护及其局限性。

Django 模板会 编码特殊字符 ,这些字符在 HTML 中都是特别危险的。 虽然这可以防止大多数恶意输入的用户,但它不能完全保证万无一失。 例如,它不会防护以下内容:

  1. <style class=>...</style>

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

同样重要的是is_safe要特别小心的用在 自定义模板标签,safe 模板标签,mark_safe ,还有 autoescape 被关闭的时候。

此外,如果您使用的是模板系统输出 HTML 以外的东西,可能会有完全不同的字符和单词需要编码。

你也应该在数据库中存储 HTML 的时候要非常小心,尤其是当 HTML 被检索然后展示出来。

跨站请求伪造 (CSRF) 防护

CSRF 攻击允许恶意用户在另一个用户不知情或者未同意的情况下,以他的身份执行操作。

Django 对大多数类型的 CSRF 攻击有内置的保护,在适当情况下你可以开启并使用它 。 然而,对于任何解决技术,都有它的局限性。 例如,CSRF 模块可以在全局范围内或为特定视图被禁用 。 您应该只在您知道在做什么的情况下操作。 还有其他 限制 如果你的网站有子域名并且在你的控制之外。

CSRF 防护 是通过检查每个 POST 请求的一个随机数(nonce)来工作。 这确保了恶意用户不能简单“回放”你网站上面表单的POST,以及让另一个登录的用户无意中提交表单。恶意用户必须知道这个随机数,它是用户特定的(存在cookie里)。

使用 HTTPS来部署的时候,CsrfViewMiddleware会检查HTTP referer协议头是否设置为同源的URL(包括子域和端口)。因为HTTPS提供了附加的安全保护,转发不安全的连接请求时,必须确保链接使用 HTTPS,并使用HSTS支持的浏览器。

使用csrf_exempt装饰器来标记视图时,要非常小心,除非这是极其必要的。

SQL 注入保护

SQl注入是一种攻击类型,恶意用户可以在系统数据库中执行任意SQL代码。这可能会导致记录删除或者数据泄露。

通过使用Django的查询集,产生的SQL会由底层数据库驱动正确地转义。然而,Django也允许开发者编写原始查询或者执行自定义sql。这些功能应该谨慎使用,并且你应该时刻小心正确转义任何用户可以控制的参数。另外,你在使用extra()的时候应该谨慎行事。

点击劫持保护

点击劫持是一类攻击,恶意站点在一个frame中包裹了另一个站点。这类攻击可能导致用户被诱导在目标站点做出一些无意识的行为。

Django在X-Frame-Options 中间件的表单中中含有 点击劫持保护 ,它在支持的浏览器中可以保护站点免于在frame中渲染。也可以在每个视图中禁止这一保护,或者配置要发送的额外的协议头。

对于任何不需要将页面包装在三方站点的frame中,或者只需要包含它的一部分的站点,都强烈推荐启用这一中间件。

SSL / HTTPS

把你的站点部署在HTTPS下总是更安全的,尽管不是在所有情况下都有效。如果不这样,恶意的网络用户可能会嗅探授权证书,或者其他在客户端和服务端之间传输的信息,或者一些情况下 — 活跃的网络攻击者 — 会修改在两边传输的数据。

如果你想要HTTPS提供保护,那么需要在你的服务器上启用它,可能还需要去做一些额外的操作

  • 如果必要的话,设置 SECURE_PROXY_SSL_HEADER,确保你已经彻底了解警告。未能实现它会导致CSRF方面的缺陷,也是很危险的!

  • 设置重定向,那样通过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安全保障,由一个已存在的成功的连接提供。HSTS通常在web服务器上面配置。

Host 协议头验证

在某些情况下,Django使用客户端提供的Host 协议头来构造URL。虽然这些值可以被审查,来防止跨站脚本攻击(XSS),但是一个假的Host值可以用于跨站请求伪造(CSRF),有害的缓存攻击,以及email中的有害链接。

因为即使表面上看起来安全的web服务器也容易被篡改主机头,Django再次在django.http.HttpRequest.get_host()这个方法中验证主机头这个ALLOWED_HOSTS的设置 Django validates Host headers against the ALLOWED_HOSTS setting in the django.http.HttpRequest.get_host() method.

验证只通过get_host()来应用;如果你的代码从request.META中直接访问Host协议头,就会绕开这一安全防护。

详见完整的ALLOWED_HOSTS文档。

警告

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

另外,就像1.3.1,如果你的配置需要它的话,Django 需要你显式开启对X-Forwarded-Host 协议头的支持(通过 USE_X_FORWARDED_HOST 设置)。

Session 会话安全

类似于部署在站点上的CSRF 限制 使不受信任的用户不能访问任何子域,django.contrib.sessions也有一些限制。详见安全中会话的话题指南

用户上传的内容

注意

考虑在云服务器或CDN上面部署静态文件来避免一些此类问题。

  • 如果你的站点接受上传文件,强烈推荐你在web服务器配置中,将这些上传限制为合理的大小,来避免拒绝服务(DOS)攻击。在Apache中,这可以简单地使用LimitRequestBody指令。

  • 如果你自己处理静态文件,确保像Apache的mod_php的处理器已关闭,它会将静态文件执行为代码。你并不希望用户能够通过上传和请求一个精心构造的文件来执行任意代码。

  • 当媒体以不遵循安全最佳做法的方式提供时,Django的媒体上传处理带来一些漏洞。具体来说,如果HTML文件包含有效的PNG标头,然后是恶意HTML,则可以将其上传为图片。此文件将通过对Django用于ImageField图像处理(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. 足以提供来自usercontent.example.com等子网域的内容。
    2. 除此之外,应用可以选择为用户上传的文件定义一个允许的文件扩展名的白名单,并且配置web服务器直处理这些文件。

额外的安全话题

虽然Django提供了开箱即用的,良好的安全保护,但是合理地部署你的应用,以及利用web服务器、操作系统和其他组件的安全保护仍然很重要。

  • 确保你的Python代码在web服务器的根目录外。这会确保你的Python代码不会意外被解析为纯文本(或者意外被执行)。
  • 小心处理任何用户上传的文件
  • Django并不限制验证用户的请求。要保护对验证系统的暴力破解攻击,你可以考虑部署一个DJango的插件或者web服务器模块来限制这些请求。
  • 秘密保存SECRET_KEY
  • 使用防火墙来限制缓存系统和数据库的访问是个好主意。