まず、既存のセキュリティ ホールへのアクセスが確実に容易になる可能性があります。
たとえば、、、、SQL クエリ、または文字列の書式設定などを介して構築された URL を実行するコードがあるとしexec
ます。また、書式設定コマンドまたはコンテキストなどeval
に渡す、たとえば、locals()
またはフィルタリングするとします。を使用すると、明らかにセキュリティ ホールが広がり、コードを攻撃する方法を見つけるのがはるかに簡単になります。これらの関数に何を渡そうとしているのかわからないからです。__dict__
eval
setattr
しかし、他に危険なことを何もしなければどうでしょうか? setattr
じゃあ安全?
それほど悪くはありませんが、それでも安全ではありません。あなたが設定している属性の名前に影響を与えることができれば、たとえば、オブジェクトに必要なメソッドを置き換えることができます。
たとえば、最初に古い値が呼び出し可能でないか、メソッド型記述子ではないかなどをチェックすることで、これを防ぐことができます。eval
同じように、関数を呼び出したり、SQL パラメーターに引用符やセミコロンを入れたりする人から保護することができます。これは、他のケースと事実上同じです。そもそもドアを開けないよりも、開いているドアへの不正な道をすべて閉じようとする方がはるかに困難です。
名前がユーザーに影響を与える可能性のあるものに由来しない場合はどうなりますか?
では、なぜ を使用しているのsetattr
でしょうか。setattr
リテラルで呼び出す正当な理由はありません。
とにかく、目前の問題を解決するためのより良い方法がしばしばあると Lattyware が言ったとき、彼はほぼ間違いなく読みやすさ、保守性、慣用性について話していました。しかし、これらのより良い方法を使用することの副作用は、多くの場合、セキュリティへの影響を回避できることです。
90% の確率で、解決策はdict
オブジェクトの代わりに a を使用することです。Javascript とは異なり、Python では同じものではなく、同じように使用することを意図していません。Adict
にはメソッド、継承、または組み込みの特殊な名前がないため、それらについて心配する必要はありません。d['foo']
の代わりに言うことができる、より便利な構文もありますsetattr(o, 'foo')
。そして、それはおそらくより効率的です。等々。しかし、最終的に a を使用する理由dict
は概念上の理由です。adict
は値の名前付きコレクションです。クラス インスタンスはモデル空間オブジェクトの表現であり、それらは同じものではありません。
では、なぜsetattr
存在するのでしょうか。
im_func
やにアクセスできるfunc_closure
、 や のようなモジュールを持っている、他のメソッドと同じように特別なメソッドを扱う、traceback
さらに言えばやなど、他の低レベルの機能と同じ基本的な理由で存在します。imp
exec
eval
まず、これらの低レベルのツールから高レベルのものを構築できます。たとえば、 をビルドするには、 またはcollections.namedtuple
のいずれかが必要exec
ですsetattr
。
第 2 に、コンパイル時にコードを変更する (または表示することさえできない) ため、実行時にコードにモンキー パッチを適用する必要があり、そのためには次のようなツールsetattr
が不可欠です。
このsetattr
機能は、よく似たものeval
で、Javascript、Tcl、またはその他のいくつかの言語から来た人々によって悪用されることがよくあります。しかし、それが永久に使用できる限り、それを言語から除外したくはありません。(TOOWTDI を文字どおりに解釈して、プログラムを 1 つだけ作成できるようにしないでください。)
しかし、それは、可能な限りこのようなものを使用する必要があるという意味ではありません. mylist.__getitem__(slice(1, 10, 2))
の代わりに書くことはありませんmylist[1:10:2]
。__getitem__
場合によっては、オブジェクトを直接呼び出したりslice
、明示的にビルドしたりできることが、コードの残りの部分をより Pythonic にするための基盤となる場合や、コードの残りの部分への感染を回避するための回避策をローカライズするための方法となる場合があります。それ以外の場合は、より明確で簡単な方法があります。