Python eval(compile(…),sandbox),global都放在sandbox中,除非在def中,为什么?

2024-04-26 04:02:15 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下因素:

def test(s):
    globals()['a'] = s

sandbox = {'test': test}
py_str = 'test("Setting A")\nglobals()["b"] = "Setting B"'
eval(compile(py_str, '<string>', 'exec'), sandbox)

'a' in sandbox # returns False, !What I dont want!
'b' in sandbox # returns True, What I want
'a' in globals() # returns True, !What I dont want!
'b' in globals() # returns False, What I want

我甚至不知道怎么问,但我希望函数的全局作用域是我打算运行它的环境,而不必在求值期间编译函数。这可能吗?在

谢谢你的意见

解决方案

^{pr2}$

Tags: 函数inpytestfalsetruewhatsetting
3条回答

外部执行上下文是在Python中静态定义的(f.func_globals是只读的),所以我想说您想要的是不可能的。原因是因为函数可能成为无效的Python,它的定义上下文在运行时被更改。如果语言允许的话,这将是向库调用中注入恶意代码的一个非常容易的途径。在

def mycheck(s): 
    return True

exec priviledged_code in {'check_password':mycheck}

通过提供可选的全局变量/局部变量对exec进行沙箱代码有许多注意事项:

  • 可选的全局变量/局部变量仅适用于沙盒中的代码。它们不会影响外部的任何东西,也不会影响到外部的任何东西,如果可以的话,就没有意义了。在

    换句话说,所谓的“沙盒”将对象test传递给exec运行的代码。要更改test看到的全局变量,还必须修改对象,而不是按原样传递它。这实际上不可能以任何方式保持它的工作,更不用说对象继续做一些有意义的事情。

  • 通过使用其他全局变量,sandbox中的任何内容都将看到内置函数。如果要在沙盒中隐藏代码中的部分或所有内置项,则需要在字典中添加一个"__builtins__"键,该键指向None(禁用所有内置项)或指向它们的版本。这也限制了对象的某些属性,例如访问函数的func_globals属性将被禁用。

  • 即使移除内置组件,沙盒仍将安全。您首先信任的仅沙盒代码。

这里有一个简单的概念证明:

import subprocess
code = """[x for x in ().__class__.__bases__[0].__subclasses__() 
           if x.__name__ == 'Popen'][0](['ls', '-la']).wait()"""
# The following runs "ls"...
exec code in dict(__builtins__=None)
# ...even though the following raises
exec "(lambda:None).func_globals" in dict(__builtins__=None)

在Python中调用函数时,它所看到的全局变量始终是在其中定义的模块的全局变量。(如果这不是真的,函数可能不起作用,它实际上可能需要一些全局值,而您不一定知道这些值是什么。)使用exec或{}指定一个全局字典只会影响代码exec'd或{}所看到的全局变量。在

如果您想让一个函数看到其他全局变量,那么您确实必须在传递给execeval()的字符串中包含函数定义。当你这样做时,函数的“module”就是它编译时所用的字符串,还有它自己的全局变量(即,你提供的那些)。在

您可以通过创建一个新函数来解决这个问题,该函数的代码对象与所调用的相同,但另一个指向全局dict的func_globals属性,但这是相当高级的黑客行为,可能不值得。不过,你还是要这样做:

# create a sandbox globals dict
sandbox = {}

# create a new version of test() that uses the sandbox for its globals
newtest = type(test)(test.func_code, sandbox, test.func_name, test.func_defaults,
                     test.func_closure)

# add the sandboxed version of test() to the sandbox
sandbox["test"] = newtest

相关问题 更多 >