【发布时间】:2013-02-27 16:41:58
【问题描述】:
我正在开发一个网络应用程序,用户可以在其中提供字符串,然后服务器会将变量代入其中。
我最好使用 PEP 3101 format() 语法,并且我正在研究在 Formatter 中覆盖方法以确保不受信任的输入的可行性。
以下是我可以看到的 .format() 的风险:
- 填充允许您指定任意长度,因此 '{:>9999999999}'.format(..) 可能会使服务器内存不足并成为 DOS。我需要禁用它。
- 格式允许您访问对象内的字段,这很有用,但令人毛骨悚然的是,您可以访问 dunder 变量并开始钻研标准库的一些内容。不知道哪里可能有一个 getattr() 有副作用或返回一些秘密。我会通过覆盖 get_field() 将属性/索引访问列入白名单。
- 我自然需要捕获一些异常。
我的假设是:
- 传统的 C 格式字符串漏洞都不适用于 Python,因为指定参数是对集合的边界检查访问,而不是直接从线程堆栈中弹出。
- 我使用的 Web 框架会转义替换到页面模板中的每个变量,只要它是输出前的最后一站,我就可以安全地避免因反转义而出现的跨站点脚本攻击。
你的想法是什么?可能的?不可能的?只是不明智?
编辑:如果您不过滤掉 dunder 变量访问,Armin Ronacher 概述了一个令人讨厌的信息泄漏,但似乎认为保护 format() 是可行的:
{local_foo.__init__.__globals__[secret_global]}
http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/
(就我个人而言,我实际上并没有在我的产品中采用不受信任的 format() 路线,但为了完整起见,我正在更新)
【问题讨论】:
-
听起来不明智。你不能用
replace()吗? -
好吧,首先,replace() 需要为字符串中可能存在的每个变量传递一个参数,这将可怕地扩展。
-
Lemmie 对此进行了扩展,因为我错过了编辑它的机会。我的用例是类似 MUD 的情况,我将使用大量潜在变量进行大量字符串格式化。我可以回到较弱的字符串格式形式,例如
string.Template,但在我的情况下,能够引用对象内部的字段也非常有用。我可以通过从每次调用中的每个参数构建每个字段的参数映射来模拟这一点,但如果有一些可以更好地扩展的东西会让人放心。 -
克雷格,也许开始定义你真正需要的
.format()功能的子集。然后您可以检查格式字符串本身,或者制作您自己的模板语言来映射到.format()格式字符串。 -
怀疑这是不明智的,同样地,使用 f-string 文字的 Python 3.6 似乎对任何用户输入的数据都有安全风险。