python - 是否存在字符串 `s` 使得 eval(repr(s)) 导致任意代码执行?

标签 python security

我在某处找到了类似的代码:

USER_CONTROLLED = 'a'
open("settings.py", "w").write("USER_CONTROLLED = %s" % eval(repr(a)))

在另一个文件中:

import settings
x = settings.USER_CONTROLLED * [0]

这是一个安全漏洞吗?

最佳答案

与 IRC 上告诉你的相反,肯定有一个 x 使 eval(repr(x)) 变得危险,所以就这样说吧,没有任何限制也是错误的。

想象一个以不同方式实现 __repr__ 的自定义对象。该文档说 __repr__它“应该看起来像一个有效的 Python 表达式,可用于重新创建具有相同值的对象”。但根本没有任何东西可以强制执行这一准则。

因此,我们可以创建一个具有自定义 __repr__ 的类,该类返回一个字符串,该字符串在评估时运行任意代码。例如:

class MyObj:
    def __repr__ (self):
        return "__import__('urllib.request').request.urlopen('http://example.com').read()"

对该类型的对象调用 repr() 显示它返回一个肯定可以计算的字符串:

>>> repr(MyObj())
"__import__('urllib.request').request.urlopen('http://example.com').read()"

在这里,这只需要向 example.com 发出请求。但正如您所看到的,我们可以在这里导入任意模块并使用它们运行代码。该代码可能会产生任何副作用。所以这绝对是危险的。

但是,如果我们将 x 限制为已知类型,并且我们知道对它们调用 repr() 会执行什么操作,那么我们确实可以说何时无法运行任意代码。例如,如果 x 是一个字符串,则 unicode_repr 的实现确保所有内容都正确转义,并且评估该对象的 repr() 将始终返回正确的字符串(甚至等于 x),而不会产生任何副作用。

所以我们应该在评估之前检查类型:

if type(a) is not str:
    raise Exception('Only strings are allowed!')

something = eval(repr(a))

请注意,我们在这里不使用 isinstance 来进行继承感知类型检查。因为我绝对可以让上面的 MyObj 继承自 str:

>>> x = MyObj()
>>> isinstance(x, str)
True
>>> type(x)
<class '__main__.MyObj'>

所以你应该在这里针对具体类型进行测试。

请注意,对于字符串,实际上没有理由调用 eval(repr(x)) 因为如上所述,这将导致 x 本身。所以你可以直接分配x

但是,对于您的实际用例,您确实遇到了一个非常大的安全问题。您想要创建一个变量赋值并将该代码存储在 Python 文件中,以便稍后由实际的 Python 解释器运行。因此,您绝对应该确保赋值的右侧不是任意代码,而是实际上是字符串的表示:

>>> a = 'runMaliciousCode()'
>>> "USER_CONTROLLED = %s" % eval(repr(a))
'USER_CONTROLLED = runMaliciousCode()'
>>> "USER_CONTROLLED = %s" % repr(a)
"USER_CONTROLLED = 'runMaliciousCode()'"

如您所见,计算 repr() 会将实际内容放在作业的右侧(因为它相当于 "..."% a) 。但这可能会导致在导入该文件时运行恶意代码。因此,您实际上应该只在那里插入字符串的 repr,而完全忘记使用 eval

关于python - 是否存在字符串 `s` 使得 eval(repr(s)) 导致任意代码执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33858507/

相关文章:

mysql - 在我的时事通讯数据库中发现 'OR 1=1/* sql injection

Python Pandas - 数据框中多列的滚动回归

security - 如何设计一个安全的 "self-destructing"电子邮件?

python multiprocessing map 对最后一个进程的错误处理

python - 当我使用PyCharm和odoo时,[Errno 2]没有这样的文件或目录,该过程以退出代码2结尾

java - 如何保护 GAE 灵活环境上的 google cron 服务任务?

php - 如何限制 PHP 对 DOCUMENT_ROOT 的文件访问

php - 保护通过 Facebook 连接完成的登录

python - 比较两个嵌套列表并保持元素的并集

python - 如何使用索引列表索引 Pandas 数据框?