You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用eval实现Hackerrank列表题是否安全?有无替代方案?

Hackerrank列表操作题中eval的安全性分析与替代方案

我用Python 3.10的match语句完成了Hackerrank的列表操作题,通过eval动态执行输入的命令。我清楚动态执行代码存在安全风险,也不认同“完全禁用eval”这类绝对观点,认为应该理解风险并掌握规避方法。我原以为自己的实现是安全的——eval仅能执行单个表达式,测试恶意注入代码时会触发语法错误,但仍不确定是否存在遗漏的风险点,也不清楚如何通过globals和locals限制eval的风险。

我的实现代码如下:

def call_fun(i_lst):
    args_num = len(i_lst)
    
    match args_num:
        case 1:
            if i_lst[0] == "print":
                eval(i_lst[0] + "(o_list)")
            else:
                eval("o_list.{}()".format(*i_lst))
        case 2:
            eval("o_list.{}({})".format(*i_lst))
        case 3:
            eval("o_list.{}({},{})".format(*i_lst))

if __name__ == '__main__':
    N = int(input())
    o_list = []
    
    for x in range(N):
        command = input().split()
        call_fun(command)

当前实现的安全风险

你的实现并不安全,存在被代码注入的风险:

  • 攻击者可以构造恶意的方法名字符串,通过属性链访问危险的内置对象。比如输入以下命令:
    __class__.__base__.__subclasses__()[132].__init__.__globals__['os'].system('echo hacked')
    
    这段输入会被eval执行为o_list.__class__.__base__.__subclasses__()[132].__init__.__globals__['os'].system('echo hacked')(),从而调用系统命令执行恶意操作。
  • eval的“单个表达式”限制并不能阻止这类攻击,因为属性访问、函数调用本身就是合法的表达式组成部分。

如何用globals和locals限制eval风险

如果一定要用eval,可以通过传入严格限制的全局和局部命名空间来降低风险:

  1. 禁用所有内置函数,只暴露必要的对象:
    # 在eval调用时传入限制后的命名空间
    eval("o_list.{}()".format(*i_lst), {'__builtins__': None}, {'o_list': o_list})
    
    但这种方式会导致print无法直接使用(因为print属于内置函数),需要单独处理print逻辑,或者手动将print加入局部命名空间。
  2. 搭配方法白名单:提前定义允许调用的列表方法,只有方法名在白名单内时才执行eval。

更安全的替代方案:避免使用eval

完全可以不用eval,通过getattr直接获取列表的方法并调用,同时配合白名单机制,这是更安全且可读性更高的实现:

def call_fun(i_lst):
    # 定义允许调用的列表方法白名单
    allowed_methods = {'append', 'insert', 'remove', 'pop', 'sort', 'reverse'}
    cmd = i_lst[0]
    
    if cmd == 'print':
        print(o_list)
    elif cmd in allowed_methods:
        # 获取列表的对应方法
        method = getattr(o_list, cmd)
        # 转换参数类型(题目中参数均为整数)
        args = map(int, i_lst[1:])
        method(*args)
    else:
        # 处理非法命令,比如抛出异常或忽略
        pass

if __name__ == '__main__':
    N = int(input())
    o_list = []
    
    for x in range(N):
        command = input().split()
        call_fun(command)

这种方式完全杜绝了代码注入风险,同时逻辑清晰,符合Python的最佳实践。

内容的提问来源于stack exchange,提问作者Juan Paulo Pérez-Tejada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:52:45