首先,它肯定可以更容易地解决现有的安全漏洞。
例如,假设您有执行exec
, eval
, SQL 查询或通过字符串格式构建的 URL 等的代码。假设您正在传递、说locals()
或过滤__dict__
到格式化命令或作为eval
上下文或其他任何东西。使用setattr
显然会扩大安全漏洞,使我更容易找到攻击代码的方法,因为您不再确定要传递给这些函数的内容。
但是,如果您不做任何其他不安全的事情怎么办?setattr
那么安全吗?
没有那么糟糕,但它仍然不安全。如果我可以影响您正在设置的属性的名称,例如,我可以在您的对象上替换我想要的任何方法。
您可以尝试通过例如首先检查旧值是否不可调用,或者不是方法类型描述符或其他方式来防止这种情况。以同样的方式,您可以尝试防止人们在 SQL 参数中调用函数eval
或在 SQL 参数中添加引号和分号等。这实际上与任何其他情况相同。尝试关闭所有通往敞开的门的非法路径比一开始就不开门要困难得多。
如果名称从不来自任何可能受用户影响的东西怎么办?
那么,在那种情况下,你为什么要使用setattr
?没有充分的理由setattr
使用文字进行调用。
无论如何,当 Lattyware 说通常有更好的方法来解决手头的问题时,他几乎肯定是在谈论可读性、可维护性和惯用性。但是使用这些更好的方法的副作用是您还经常避免任何安全隐患。
90% 的情况下,解决方案是使用 adict
而不是对象。与 Javascript 不同,它们在 Python 中不是一回事,而且它们的使用方式也不相同。Adict
没有方法、继承或内置的特殊名称,因此您不必担心这些。它还具有更方便的语法,您可以在其中说d['foo']
而不是setattr(o, 'foo')
. 而且它可能更有效。等等。但归根结底,使用 a 的dict
原因是概念上的原因:adict
是值的命名集合;类实例是模型空间对象的表示,它们不是一回事。
那么,为什么会setattr
存在呢?
它的存在与其他低级功能相同的基本原因,例如能够访问im_func
or func_closure
,或者具有类似traceback
and的模块imp
,或者像对待任何其他方法一样处理特殊方法,或者就此而言exec
and eval
。
首先,您可以使用这些低级工具构建更高级别的东西。例如,要构建collections.namedtuple
,您需要exec
或setattr
。
其次,您有时需要在运行时对代码进行猴子补丁,因为您无法在编译时修改它(甚至可能看到它),而类似的工具setattr
对于这样做是必不可少的。
这个setattr
特性——很像eval
——经常被来自 Javascript、Tcl 或其他一些语言的人滥用。但只要它可以永久使用,您就不想将其从语言中删除。(TOOWTDI 不应该被理解为只能编写一个程序。)
但这并不意味着你应该尽可能地使用这些东西。你不会写mylist.__getitem__(slice(1, 10, 2))
而不是mylist[1:10:2]
. 有时,能够__getitem__
直接调用或显式构建slice
对象是让其余代码更加pythonic的基础,或者是本地化解决方法以避免感染其余代码的方法。否则,有更清晰和更简单的方法可以做到这一点。