众所周知,在 python 中可以使用 exec 函数来执行包含 python 源代码的字符串:
1 2 3 4 5 6 7 8 |
>>> code = ''' ...: a = "hello" ...: print(a) ...: ''' >>> exec(code) hello >>> a 'hello' |
exec 函数的这个功能很是强大,慎用。如果一定要用的话,那么就需要注意一下下面这些安全相关的问题。
全局变量和内置函数
在 exec 执行的代码中,默认可以访问执行 exec 时的局部变量和全局变量, 同样也会修改全局变量。如果 exec 执行的代码是根据用户提交的数据生产的话,这种默认行为就是一个安全隐患。
如何更改这种默认行为呢?可以通过执行 exec 函数的时候再传两个参数的方式来 修改这种行为(详见 之前 关于 exec 的文章):
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> g = {} >>> l = {'b': 'world'} >>> exec('hello = "hello" + b', g, l) >>> l {'b': 'world', 'hello': 'helloworld'} >>> g {'__builtins__': {...}} >>> hello --------------------------------------------------------------------------- NameError Traceback (most recent call last) ... NameError: name 'hello' is not defined |
如果要限制使用内置函数的话,可以在 globals 参数中定义一下 __builtins__ 这个 key:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> g = {} >>> l = {} >>> exec('a = int("1")', g, l) >>> l {'a': 1} >>> g = {'__builtins__': {}} >>> exec('a = int("1")', g, l) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'int' is not defined >>> |
现在我们限制了访问和修改全局变量以及使用内置函数,难道这样就万事大吉了吗? 然而并非如此,还是可以通过其他的方式来获取内置函数甚至 os.system 函数。
另辟蹊径获取内置函数和 os.system
通过函数对象:
1 2 3 4 5 6 |
>>> def a(): pass ... >>> a.__globals__['__builtins__'] >>> a.__globals__['__builtins__'].open <built-in function open> |
通过内置类型对象:
1 2 3 4 5 6 7 |
>>> for cls in {}.__class__.__base__.__subclasses__(): ... if cls.__name__ == 'WarningMessage': ... b = cls.__init__.__globals__['__builtins__'] yon-h"> b = cls.__init__.__globals__['__builtins__'] b1f88fa5f833971999" class="crayon-syntax crayon-theme-github crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-always" style=" margin-top: 12px; margin-bottom: 12px; font-size: 13px !important; line-height: 15px !important;">
exec 函数的这个功能很是强大,慎用。如果一定要用的话,那么就需要注意一下下面这些安全相关的问题。 全局变量和内置函数在 exec 执行的代码中,默认可以访问执行 exec 时的局部变量和全局变量, 同样也会修改全局变量。如果 exec 执行的代码是根据用户提交的数据生产的话,这种默认行为就是一个安全隐患。 如何更改这种默认行为呢?可以通过执行 exec 函数的时候再传两个参数的方式来 修改这种行为(详见 之前 关于 exec 的文章):
如果要限制使用内置函数的话,可以在 globals 参数中定义一下 __builtins__ 这个 key:
现在我们限制了访问和修改全局变量以及使用内置函数,难道这样就万事大吉了吗? 然而并非如此,还是可以通过其他的方式来获取内置函数甚至 os.system 函数。 另辟蹊径获取内置函数和 os.system通过函数对象:
通过内置类型对象:
|