已发布的安全版本
今天,Django 团队发布了多个版本——Django 1.2.6 和 Django 1.3.1——以解决向我们报告的安全问题。此外,本公告还包含关于其他几个问题的建议,虽然这些问题不需要更改 Django 本身,但会引起 Django 用户的关注。
我们鼓励所有用户立即升级 Django 并实施这些建议。
会话操纵
Django 的会话框架,django.contrib.sessions
,可配置为使用多种后端中的任何一种来存储会话数据。Django 自身提供的一种这样的后端与 Django 的缓存框架集成,以使用缓存来存储会话数据。
当使用基于内存的会话和缓存以这种方式配置时,Django 会话直接存储在缓存的根命名空间中,使用会话标识符作为键。
当与在缓存中存储用户提供数据的应用程序结合使用时,这会导致潜在的攻击;如果攻击者可以导致使用作为有效会话标识符的键缓存数据,Django 的会话框架将把该数据(只要它是类似字典的对象)视为会话,从而允许将任意数据插入会话,只要攻击者知道会话密钥即可。
为了减轻这种情况,用于存储会话的密钥现在将在缓存中使用命名空间,而不是存储在缓存的根命名空间中。请注意,虽然这会使部署更新的会话代码的任何站点的当前会话失效,但我们并不认为这是一种向后不兼容性,因为会话数据旨在是短暂的。
通过 URLField 进行的拒绝服务攻击
Django 的模型系统包含一种字段类型——URLField
——它验证提供的 value 是否为有效的 URL,如果布尔关键字参数verify_exists
为 true,则尝试通过向其发出请求来验证提供的 URL 是否也能解析。
默认情况下,Python 中的底层套接字库没有超时。这可能以三种不同的方式表现为安全问题。
- 攻击者可以提供响应缓慢的 URL。每个请求都会占用服务器进程一段时间;如果攻击者能够发出足够的请求,他们可以占用所有可用的服务器进程。
- 攻击者可以提供其控制下的 URL,并且该 URL 将无限期地保持打开连接。由于缺少超时,尝试验证 URL 的 Django 进程也将无限期地旋转。重复此操作很容易占用所有可用的服务器进程。
- 攻击者可以提供其控制下的 URL,该 URL 不仅保持连接打开,而且还发送无休止的随机垃圾数据流。此数据将导致 Django 进程的内存使用量(该进程将在内存中保存响应)无限增长,从而不仅消耗服务器进程而且消耗服务器内存。
为了解决这个问题,URLField
将按以下方式修改:verify_exists
参数将默认为 false 值;对于支持设置超时的较新 Python 版本,将设置 10 秒的超时;verify_exists
将被弃用并最终从 Django 的未来版本中删除,因为它的效用不足以保证它可能造成的风险。
URLField 重定向
用于验证 URL 的正则表达式用于在发出检查以验证其是否存在之前检查提供的 URL,但如果该 URL 响应请求发出重定向,则不会对生成的重定向 URL 执行验证,包括对支持的协议(HTTP、HTTPS 和 FTP)的基本检查。
这为攻击者创造了一个小的窗口来获取例如服务器布局的知识;例如,重定向到file://
URL 将告诉攻击者给定文件是否本地存在于服务器上。
此外,尽管 Django 发出的初始请求对 HTTP/HTTPS 使用 HEAD 方法,但对重定向目标的请求使用 GET 方法。这可能会为隐式信任来自本地机器/网络的 GET 请求的系统造成进一步的问题。
这个问题最终源于 Python 本身的一个错误,该错误已得到修复,但由于该修复似乎尚未得到广泛使用,我们将修改 Django 的 URL 检查功能(在由于弃用而删除之前的剩余生命周期内)以使用允许的协议白名单进行重定向,并将重定向视为存在的 URL,但不遵循重定向。
主机头缓存中毒
在多个地方,Django 本身(独立于开发人员)生成完整的 URL(例如,在发出 HTTP 重定向时)。目前,这使用来自请求的 HTTP Host 标头值来构造 URL,这打开了一个潜在的缓存中毒向量:攻击者可以使用他或她选择的 Host 标头提交请求,接收使用该 Host 标头构造 URL 的响应,并且——如果该响应被缓存——进一步的请求将使用包含攻击者选择的 Host 的 URL 从缓存中提供。
为了解决这个问题,Django 现在在构造完整 URL 时默认忽略 X-Forwarded-Host 标头。如果您的站点在您确信正确设置和验证 X-Forwarded-Host 的代理后面提供服务,您可以通过USE_X_FORWARDED_HOST设置启用它。但是,除非应用以下建议(在标记为“主机标头和 CSRF”的建议中),否则 Django 本身和用户开发的代码也将容易受到这种类型的攻击。
建议:主机标头和 CSRF
在某些 Web 服务器配置中,攻击者可以绕过 Django 的 CSRF 保护机制。攻击的工作原理如下:
- 攻击者在 attacker.com 处托管一个页面,并为子域 subdomain.attacker.com 设置 CNAME,指向目标站点 victim.com。
- attacker.com 的访问者会看到一个使用 JavaScript 向 subdomain.attacker.com 发送请求的站点。这将被同源策略允许,攻击者将能够控制发送这些请求的 Cookie 和数据,包括提供 CSRF Cookie 和 POST 请求的令牌。
- 由于 CNAME,对 subdomain.attacker.com 的请求将发送到 victim.com。如果受害者的 Web 服务器未验证传入的 HTTP Host 标头(或具有通配符虚拟主机响应与特定命名虚拟主机不匹配的任何请求),则它将把该请求传递给 Django,并且 Django 的 CSRF 机制将允许该请求,因为存在 CSRF Cookie 和令牌。
据我们所知,这不会允许通常与 CSRF 漏洞相关的恶意数据操纵或权限升级类型(因为攻击者无法访问或操纵受害者站点的 Cookie/会话),但仍然被认为是 CSRF 漏洞。
为了避免这种潜在的攻击,我们建议 Django 用户确保他们的 Web 服务器配置始终根据预期主机名验证传入的 HTTP Host 标头,不允许没有 Host 标头的请求,并且 Web 服务器未配置为具有将请求转发到 Django 应用程序的通配符虚拟主机。
建议:跨子域 CSRF 攻击
由于 HTTP Cookie 的性质,可以从将对整个域有效的子域设置 Cookie。这意味着控制子域的攻击者可以例如设置对整个域有效的 CSRF Cookie。
这本身并不是 Django 中的错误,而是 Django 用户应该注意的潜在攻击媒介;为了避免这种攻击,请确保您的域的子域仅在受信任用户的控制下(这是标准的最佳实践)。Django 的 CSRF 文档中包含了一些关于此的说明。
建议:DEBUG 页面和敏感 POST 数据
当 DEBUG 设置为 True 时,Django 将通过生成格式良好的错误页面来处理异常,包括完整的回溯和 HTTP 请求和相关设置的显示。
敏感设置(如密码)在此显示中已被屏蔽,但默认情况下,使用 HTTP 请求提交的数据不会被屏蔽。因此,例如,登录视图中的错误可能导致 DEBUG 页面显示纯文本密码(来自 POST 数据)。
为了减轻这种情况,Django 的开发版本添加了两个装饰器,它们将隐藏调试报告中的特定信息。建议处理敏感数据的用户阅读这些装饰器的文档并适当地使用它们。
受影响的版本
上述所有问题都存在于以下版本的 Django 中:
- Django 开发主干
- Django 1.3
- Django 1.2
解决方案
补丁已应用于 Django 主干以及 1.3 和 1.2 发布分支,这些补丁解决了上述三个安全问题。补丁可以直接从以下 changeset 中获取:
- Django 主干:会话问题 Changeset 16759,URLField 问题 Changeset 16760,主机头问题 Changeset 16758。
- Django 1.3:会话问题 Changeset 16762,URLField 问题 Changeset 16763,主机头问题 Changeset 16761。
- Django 1.2:会话问题 Changeset 16765,URLField 问题 Changeset 16766,主机头问题 Changeset 16764。
已发布以下新版本:
由于 Django 主干目前处于预发布 alpha 状态,强烈建议用户不要从中运行生产部署;但是,如果您目前正在这样做,我们强烈建议您立即升级到最新的主干,其中包含上述补丁。
致谢
上述前三个安全问题均由 Paul McMillan 向我们报告,由于他在识别和帮助减轻 Django 中的安全问题方面的工作卓著,他现在已被添加到 Django 核心开发团队。上述问题的补丁也主要由 Paul 开发。
主机头缓存中毒漏洞是由核心团队通过一篇报道此类攻击可能性的文章发现的。
跨子域 CSRF 报告最初由 Mozilla 提供。
DEBUG 页面中显示敏感数据的问题以及减轻此问题的方法均由 Julien Phalip 提供,他也最近加入了 Django 核心团队。
关于安全的总体说明
与往常一样,我们要求通过私人电子邮件向 security@djangoproject.com 报告潜在的安全问题,而不是通过 Django 的 Trac 实例或 django-developers 列表。
如果您是或代表 Django 的第三方分销商,并且未从 Django 发布管理员处收到有关此公告的通知电子邮件,请联系james@b-list.org
。