我使用 Python 3.11 引入的 switch 语句解决了这个 Hackerrank 挑战。我使用
eval
动态执行输入中给出的命令。
但是,我知道动态执行代码可能会导致安全风险。我已经读过关于该主题的旧讨论:为什么使用“eval”是一种不好的做法?所以我想知道是否有其他方法来使用它,或者这可能是 eval 的有效用例。
我真的不喜欢诸如“始终避免这种情况”之类的陈述,因为我们有使用它的命令,如果我们应该始终避免它,那么为什么不直接删除它们呢?对我来说,最好了解风险并知道如何避免它们,并在没有有效用例时给出有效用例和替代方案的示例。
对我来说,下面的代码是一个有效的用例,但如果您认为存在真正的风险,我将不胜感激其他意见。我主要是 Ruby 开发人员,所以我仍然不知道 Python 的所有细微差别。
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)
我知道我将收到与列表方法(追加、插入、排序等)和打印语句匹配的字符串。这些方法及其参数是我的输入列表 (i_lst)。
我认为这是 eval 的有效用例,因为 eval 只能执行单个表达式,并且我附加到列表命令,因此如果输入中有意包含恶意代码,则会引发语法错误。我在我的翻译中尝试过这个案例,以确保:
a_lst = ["append", "5); print('Unsafe'"]
所以,如果我可以引入恶意代码,我就可以执行
append
,然后执行任何恶意代码。但是,当我使用 eval 运行它时,它给出了以下错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in call_fun
File "<string>", line 1
o_lst.append(5); print('Unsafe')
^
SyntaxError: invalid syntax
因此,我倾向于认为这是一个安全的实现。
我阅读了使用全局变量和局部变量的建议通过 eval 限制安全风险,但不确定如何实现,如果在这种情况下,那就太好了。
是否有任何其他情况可能存在我所遗漏的安全风险,因此最好避免“评估”?或者您也认为这是一个安全有效的用例?
这是评估的有效用例吗
一般来说,不会。假装它不存在,您最终会得到更清洁、更安全的解决方案:
def call_fun(cmd):
match cmd:
case ["print"]:
print(o_list)
case ["sort"]:
o_list.sort()
case ["pop"]:
o_list.pop()
case ["reverse"]:
o_list.reverse()
case ["remove", value]:
o_list.remove(int(value))
case ["append", value]:
o_list.append(int(value))
case ["insert", index, value]:
o_list.insert(int(index), int(value))
或者如果你坚持的话,
def call_fun(cmd):
match cmd:
case ["print"]:
print(o_list)
case [("sort" | "pop" | "reverse" | "remove" | "append" | "insert") as method, *args]:
getattr(o_list, method)(*map(int, args))
是的,如果卡中存在恶意输入,您的代码很容易受到攻击 – 可以执行任意代码(网上有很多关于如何利用
eval
的示例),但也仅适用于以下情况:
append open("/etc/passwd").read()