Python用eval实现的装饰器是否存在恶意注入安全风险?
问题解答
原eval实现的安全风险
在*keys参数仅由开发者配置的前提下,直接被入侵的门槛较高,但仍然存在明确的攻击路径:
- 如果用户可以传入自定义类的实例作为参数,攻击者可以构造恶意类重写魔术方法触发执行,比如:
class EvilObj: def __add__(self, other): # 此处可插入任意恶意操作,比如执行系统命令、删库 __import__('os').system('rm -rf /*') return ""
当攻击者将该类实例作为you参数传入时,eval执行you + " " + me的加法操作会自动触发__add__方法,直接执行恶意代码。即使表达式没有运算,只要访问对象的属性、方法都可能触发预置的恶意逻辑。
- 如果开发者配置的keys表达式中存在
eval、exec、getattr这类可以执行动态逻辑的函数,攻击者只要传入对应格式的字符串参数即可触发代码执行,比如开发者写了'eval(you)',攻击者传"__import__('os').system('format C:')"就会直接执行恶意操作。
强制转str的方案不能完成安全过滤
这个修改只能规避部分运算符重载的攻击,但仍然存在漏洞:
- 攻击者依旧可以在自定义类的
__str__方法中写入恶意代码,你执行str(func_args[func_arg_key])转换参数类型时就会直接触发执行,不需要等到eval运行。 - 如果keys表达式里存在危险函数调用,字符串类型的参数一样可以用来注入代码,和转不转str没有关系。
- 这个方案还会破坏业务兼容性:如果表达式需要用到参数本身的数值/对象能力(比如给int类型的用户ID做取模分片),强制转str之后原逻辑会直接失效。
lambda方案安全性远高于eval方案
lambda方案几乎彻底规避了代码注入风险,原因如下:
- lambda是Python原生的可调用对象,逻辑在代码编写阶段就已经固定,不存在运行时动态解析字符串执行未知代码的可能性,从根上解决了eval的动态执行风险。
- 所有逻辑对IDE、静态检查工具可见,开发者可以很容易发现代码中的危险操作,不会像字符串表达式那样藏着漏洞到运行时才暴露。
- 即使攻击者传入恶意对象,能触发的只有lambda中显式调用的方法(比如你显式写
str(d['you'])才会调用__str__),这类风险是所有接收用户自定义对象的Python代码都要面对的通用风险,和你用不用eval无关,你可以通过增加基础类型校验的方式彻底解决。 - 除了安全之外,lambda方案的可维护性也高得多,语法错误在编码阶段就会暴露,不会像字符串表达式那样到线上运行时才出问题。
内容的提问来源于stack exchange,提问作者winwin
相关产品推荐
相关产品推荐

