Django 1.6.3 发行说明 — Django 文档
Django 1.6.3 发行说明
2014 年 4 月 21 日
Django 1.6.3 修复了 1.6.2 中的几个错误,包括三个安全问题,并进行了一个向后不兼容的更改:
使用 reverse() 执行意外代码
Django 的 URL 处理基于正则表达式模式(表示 URL)到可调用视图的映射,Django 自己的处理包括将请求的 URL 与这些模式进行匹配,以确定要调用的适当视图。
Django 还提供了一个方便的函数——reverse()
——它以相反的方向执行这个过程。 reverse()
函数获取有关视图的信息并返回将调用该视图的 URL。 鼓励应用程序开发人员使用 reverse()
,因为 reverse()
的输出始终基于当前的 URL 模式,这意味着开发人员在更改 URL 时无需更改其他代码。
reverse()
的一个参数签名是将虚线 Python 路径传递给所需的视图。 在这种情况下,Django 将导入由虚线路径指示的模块,作为生成结果 URL 的一部分。 如果这样的模块有导入时的副作用,这些副作用就会发生。
因此,鉴于以下条件,攻击者可能会导致意外的代码执行:
- 存在一个或多个基于用户输入构建 URL 的视图(通常,查询字符串中的“next”参数指示成功完成操作后重定向的位置)。
- 攻击者知道服务器的 Python 导入路径上存在一个或多个模块,这些模块在执行代码时会对导入产生副作用。
为了解决这个问题,reverse()
现在将只接受和导入基于项目URL模式配置中列出的包含视图的模块的虚线路径,以确保只有开发人员打算使用的模块以这种方式导入可以或将被导入。
匿名页面的缓存可能会泄露 CSRF 令牌
Django 包括一个 缓存框架 和一个用于 防止跨站点请求伪造 (CSRF) 攻击的系统 。 CSRF 保护系统基于在 cookie 中发送给客户端的随机随机数,该 cookie 必须由客户端在未来的请求中发送,并且在表单中,一个隐藏值必须与表单一起提交回来。
缓存框架包括将响应缓存到匿名(即未经身份验证)客户端的选项。
当对给定页面的第一个匿名请求来自没有 CSRF cookie 的客户端时,缓存框架也会缓存 CSRF cookie 并将相同的随机数提供给其他没有 CSRF cookie 的匿名客户端。 这可以允许攻击者获取有效的 CSRF cookie 值并执行绕过 cookie 检查的攻击。
为了解决这个问题,缓存框架将不再缓存此类响应。 对此的启发式将是:
- 如果传入的请求没有提交任何 cookie,并且
- 如果响应确实发送了一个或多个 cookie,并且
- 如果在响应上设置了
Vary: Cookie
标头,则不会缓存响应。
MySQL 类型转换
众所周知,MySQL 数据库会对某些查询进行“类型转换”; 例如,当查询包含字符串值的表,但使用基于整数值进行过滤的查询时,MySQL 将首先静默将字符串强制转换为整数并基于该值返回结果。
如果执行查询时没有先将值转换为适当的类型,这可能会产生意想不到的结果,类似于查询本身已被操作时会发生的情况。
Django 的模型字段类知道它们自己的类型,并且大多数此类类在查询之前将查询参数显式转换为正确的数据库级类型。 但是,三个模型字段类没有正确转换它们的参数:
FilePathField
GenericIPAddressField
IPAddressField
这三个字段已更新,以便在查询之前将它们的参数转换为正确的类型。
此外,现在通过文档警告自定义模型字段的开发人员,以确保他们的自定义字段类将执行适当的类型转换,以及 raw() 和 extra() 查询方法的用户 –允许开发人员提供原始 SQL 或 SQL 片段 - 将建议他们确保在执行查询之前执行适当的手动类型转换。
select_for_update() 需要交易
从历史上看,使用 select_for_update() 的查询可以在事务之外的自动提交模式下执行。 在 Django 1.6 之前,Django 的自动事务模式允许使用它来锁定记录,直到下一次写入操作。 Django 1.6 引入了数据库级自动提交; 从那时起,在这样的上下文中执行会使 select_for_update()
的效果无效。 因此,现在假定它是一个错误并引发异常。
进行此更改是因为此类错误可能是由于包含需要全局事务的应用程序(例如 :设置:`ATOMIC_REQUESTS ` 设置True
) 或 Django 旧的自动提交行为,在没有它们的项目中运行; 此外,此类错误可能表现为数据损坏错误。
如果您在作为 TransactionTestCase 而不是 TestCase 的子类的测试类中使用 select_for_update()
,则此更改可能会导致测试失败。
其他错误修正和更改
- 从 GeoIP 库中检索的内容现在可以从其默认的
iso-8859-1
编码 (:ticket:`21996`) 正确解码。 - 修复了
AttributeError
(:ticket:`21566`)。 - 修复了使用
F() + timedelta()
的QuerySet
在其查询被多次编译时崩溃的问题 (:ticket:`21643`)。 - 防止 IntegerField 子类的自定义
widget
类属性被__init__
方法中的代码覆盖 (:ticket:`22245`)。 - 改进了 strip_tags() 准确性(但它仍然不能保证 HTML 安全的结果,如文档中所述)。
- 修复了 django.contrib.gis SQL 编译器中针对非具体字段的回归 (:ticket:`22250`)。
- 修复了 ModelAdmin.preserve_filters 在运行带有 URL 前缀 (:ticket:`21795`) 的站点时。
- 修复了未设置
PATH
环境变量 (:ticket:`22256`) 时find_command
管理实用程序崩溃的问题。 - 修复了 Windows 上的 :djadmin:`changepassword` (:ticket:`22364`)。
- 避免了 MySQL 上的阴影死锁异常 (:ticket:`22291`)。
- 在
_set_autocommit
(:ticket:`22321`) 中包装数据库异常。 - 修复关闭数据库连接或数据库服务器断开连接时的原子性(:ticket:`21239` 和 :ticket:`21202`)
- 修复了
prefetch_related
中导致相关对象查询包含不必要连接的回归 (:ticket:`21760`)。
此外,Django 的销售版本 6,django.utils.six
已升级到最新版本 (1.6.1)。