Python的字符串.format()可以安全地用于不受信任的格式字符串吗?

时间:2013-03-12 08:42:55

标签: python security

我正在开发一个网络应用程序,用户可以在其中提供服务器然后将变量替换为的字符串。

我最好使用PEP 3101 format()语法,我正在研究在Formatter中覆盖方法的可行性,以确保它对不受信任的输入是安全的。

以下是我可以看到的.format()风险:

  • Padding允许您指定任意长度,因此'{:> 9999999999}'。format(..)可以使服务器内存不足并成为DOS。我需要禁用它。
  • 格式允许您访问对象内部的字段,这很有用,但令人毛骨悚然的是,您可以访问dunder变量并开始钻取标准库的位。没有人知道哪里可能有getattr()有副作用或返回秘密。我会通过覆盖get_field()来将属性/索引访问列入白名单。
  • 我自然需要抓住一些例外。

我的假设是:

  • 传统的C格式字符串漏洞都不适用于Python,因为指定参数是对集合的边界检查访问,而不是直接弹出线程的堆栈。
  • 我正在使用的Web框架转义了每个被替换为页面模板的变量,只要它是输出前的最后一站,我就可以避免因转义而产生的跨站点脚本攻击。

你有什么想法?可能?不可能?仅仅是不明智的?


编辑:如果你没有过滤掉dunder变量访问,Armin Ronacher概述了一个令人讨厌的信息泄漏,但似乎认为安全格式()是可行的:

{local_foo.__init__.__globals__[secret_global]}

http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/

(就我个人而言,我实际上并没有在我的产品中使用不受信任的format()路由,但为了完整起见我正在更新)

2 个答案:

答案 0 :(得分:7)

本能很好。是的,能够提供任意格式字符串的攻击者是python下的漏洞。

  • 拒绝服务可能是最容易解决的问题。在 在这种情况下,限制字符串的大小或运算符的数量 在字符串中将缓解此问题。应该有一个 设置没有合理用户需要生成字符串的地方 比X更多的变量,这个计算量没有风险 在DoS攻击中被利用。
  • 能够访问对象内的属性可能很危险。 但是,我不认为Object父类有任何用处 信息。提供给格式的对象必须包含 敏感的东西。无论如何,这种符号可以限制 使用正则表达式
  • 如果格式字符串是用户提供的,那么用户可能需要 知道调试的错误消息。但是,错误消息可以 包含敏感信息,如本地路径或类名。使 一定要限制攻击者可以获得的信息。

查看您不希望用户使用正则表达式的python format string specification和禁止的功能。

答案 1 :(得分:0)

此简单的Formatter覆盖阻止用户访问属性。它仍然允许格式化和转换类型。

from string import Formatter
class SafeFormatter(Formatter):
        def get_field(self, field_name, args, kwargs):
            if '.' in field_name or '[' in field_name:
                raise Exception('Invalid format string.')
            return super().get_field(field_name,args,kwargs)

form = SafeFormatter()
fname = form.format(format,num=1,id='hello')