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

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())。没有任何副作用。

因此,我们应该在评估类型之前检查其类型:

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

something = eval(repr(a))


请注意,我们此处不使用x进行继承感知类型检查。因为我绝对可以使上述的isinstanceMyObj继承:

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


因此,您实际上应该在此处针对具体类型进行测试。

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

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

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


如您所见,评估x会将实际内容放在分配的右侧(因为它等效于repr())。但这会导致导入该文件时运行恶意代码。因此,您实际上应该只在其中插入字符串的repr,而完全忘记完全使用"…" % a了。

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

10-12 06:45