我知道不建议在eval()
不受信任的输入上使用,但我想看看这个清理器在哪里失败了。它使用白名单仅允许无害的内置函数,并且如果调用任何 dunder 属性,它会立即放弃。(注意:它进行字符串搜索.__
而不仅仅是__
因为我想允许诸如 之类的东西foo.bar__baz
)。
def safe_eval(code: str) -> Any | None:
if '.__' in code:
raise ValueError
allowed_builtins = [
'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr',
'complex', 'dict', 'divmod', 'enumerate', 'filter', 'float', 'format', 'frozenset',
'hasattr', 'hash', 'hex', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'list',
'map', 'max', 'min', 'next', 'object', 'oct', 'ord', 'pow', 'range', 'repr', 'reversed',
'round', 'set', 'slice', 'sorted', 'str', 'sum', 'tuple', 'zip'
]
return eval(
code,
globals={
'__builtins__': {
builtin : getattr(__builtins__, builtin) for builtin in allowed_builtins
}
},
locals={},
)
回复:“你为什么要这样做?”我希望能够根据用户输入过滤 Python 对象。这些对象是应用程序中“会话”的“有效负载”,因此允许用户根据有效负载内容的任意表达式过滤会话(例如len(payload.things) > 12
)将是一个有用的功能。
所以我的问题是:什么输入字符串会允许攻击者访问 eval“外部”的数据,即脚本中的变量或访问操作系统?
只需添加一个空格:
. __
标准绕过可以正常工作。如下所示:
说真的,不要使用
eval
。这些临时的清理程序永远无法覆盖整个攻击面,即使奇迹般地做到了,攻击面也会随着每个 Python 版本的更新而扩大。