38

私はこれを複数の場所で何度も見てきましたが、なぜこれが当てはまるのかについて満足のいく説明を見つけたことはありません.

そのため、うまくいけば、ここで 1 つ提示されます。なぜ (少なくとも一般的には) and を使用exec()してはいけないのeval()でしょうか?

編集: この質問は Web サーバーに関するものだと思っている人がいるようですが、そうではありません。サニタイズされていない文字列が渡されるのが悪い理由がわかりますexec。非Webアプリケーションでは悪いですか?

4

11 に答える 11

29

同じ効果を得るには、より明確で直接的な方法がよくあります。複雑な文字列を作成してexecに渡すと、コードを追跡したり、テストしたりするのが困難になります。

例:文字列のキーと値を読み取り、対応するフィールドをオブジェクトに設定するコードを記述しました。それはこのように見えました:

for key, val in values:
    fieldName = valueToFieldName[key]
    fieldType = fieldNameToType[fieldName]
    if fieldType is int:
        s = 'object.%s = int(%s)' % (fieldName, fieldType) 
    #Many clauses like this...

exec(s)

そのコードは単純なケースではそれほどひどいものではありませんが、新しいタイプが登場するにつれて、ますます複雑になりました。バグがあった場合、それらはexecの呼び出しで常にトリガーされたため、スタックトレースはバグを見つけるのに役立ちませんでした。最終的に、各フィールドを明示的に設定する、少し長くて賢くないバージョンに切り替えました。

コードを明確にするための最初のルールは、コードの各行は、その近くの行だけを見れば理解しやすいものでなければならないということです。これが、goto変数とグローバル変数が推奨されない理由です。execとevalを使用すると、このルールを簡単に破ることができます。

于 2009-12-19T17:04:00.600 に答える
17

exec と eval が必要なときは、ええ、本当に必要です。

しかし、これらの関数 (および他のスクリプト言語の同様の構造体) の実際の使用法の大部分は完全に不適切であり、より高速で安全でバグの少ない他の単純な構造体に置き換えることができます。

適切なエスケープとフィルタリングにより、exec と eval を安全に使用できます。しかし、問題を解決するために exec/eval に直行するようなコーダー (言語が利用できる他の機能を理解していないため) は、その処理を正しく行うことができるようなコーダーではありません。文字列処理を理解せず、やみくもに部分文字列を連結するだけで、脆弱で安全でないコードを作成する人になるでしょう。

ルアーオブストリングスです。文字列セグメントをあちこちに放り込むのは簡単に見え、ナイーブなコーダーをだまして、自分が何をしているのか理解していると思い込ませます。しかし、経験上、一部のコーナー (またはそれほどコーナーではない) のケースでは、ほとんどの場合、結果が間違っており、多くの場合、潜在的なセキュリティへの影響があることが示されています。これが、eval が悪だと言う理由です。これが、regex-for-HTML が悪だと言う理由です。これが、SQL パラメーター化をプッシュする理由です。はい、手動の文字列処理でこれらすべてを正しく行うことができます

于 2009-12-19T18:20:30.560 に答える
13

eval() および exec() は、遅延プログラミングを促進する可能性があります。さらに重要なことは、実行中のコードが設計時に作成されていない可能性があるため、テストされていないことを示しています。つまり、動的に生成されたコードをどのようにテストするのでしょうか? 特にブラウザ間で。

于 2009-12-19T17:22:19.480 に答える
12

セキュリティは別として、それらが引き起こす複雑さのために望ましくないとマークされることがよくありますevalexec呼び出しを見るevalと、その背後で実際に何が起こっているのかがわからないことがよくあります。これは、通常は変数内にあるデータに作用するためです。これにより、コードが読みにくくなります。

インタープリターの全機能を呼び出すことは、非常にトリッキーな場合にのみ使用すべき強力な武器です。ただし、ほとんどの場合、これは避けるのが最善であり、より単純なツールを使用する必要があります。

とはいえ、すべての一般化と同様に、これには注意してください。場合によっては、exec と eval が役立つことがあります。しかし、それらを使用するには十分な理由が必要です。許容される用途については、この投稿を参照してください。

于 2009-12-19T17:14:30.123 に答える
9

ほとんどの回答がここで言っていることとは対照的に、execは実際にはPythonで超完全なデコレータを構築するためのレシピの一部です。これは、装飾された関数に関するすべてを正確に複製して、ドキュメントなどの目的で同じ署名を生成できるためです。これは、広く使用されているデコレータモジュール(http://pypi.python.org/pypi/decorator/)の機能の鍵です。exec / evalが不可欠な他のケースは、Pythonで解析されたテンプレート言語(MakoやJinjaなど)など、あらゆる種類の「解釈されたPython」タイプのアプリケーションを構築する場合です。

したがって、これらの関数の存在が「安全でない」アプリケーションまたはライブラリの即時の兆候であるとは限りません。単純なjavascriptyの方法でそれらを使用して、着信JSONなどを評価します。そう、それは非常に安全ではありません。しかし、いつものように、それはあなたがそれを使う方法のすべてであり、これらは非常に重要な機能です。

于 2009-12-20T00:22:00.880 に答える
6

私はeval()過去に(そして今でも時々使用しています)、迅速で汚い操作中にデータをマッサージするために使用しました。これは、仕事を成し遂げるために使用できるツールキットの一部ですが、他の回答で言及されているすべての理由により、コマンドラインツールやスクリプトなど 、本番環境で使用する予定のものには決して使用しないでください。

ユーザーが正しいことをすることを信頼することはできません。ほとんどの場合、彼らはそうしますが、あなたが思いもよらなかったすべてのことを実行し、あなたが予期していなかったすべてのバグを見つけてくれることを期待する必要があります。これはまさにeval()、ツールから責任へと変わるところです。

この完璧な例は、QuerySet. クエリに渡されるパラメーターは、次のようなキーワード引数を受け入れます。

results = Foo.objects.filter(whatever__contains='pizza')

プログラムで引数を割り当てている場合は、次のようにすることを考えるかもしれません。

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))

しかし、 を使用しないより良い方法が常にありますeval()。これは、参照によって辞書を渡すことです。

results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} ) 

このようにすることで、パフォーマンスが向上するだけでなく、より安全でより Pythonic になります。

この話の教訓?

の使用はeval()小さなタスク、テスト、および本当に一時的なものには問題ありませんが、ほぼ確実にそれを行うためのより良い方法があるため、永続的な使用には適していません!

于 2009-12-19T18:12:13.977 に答える
5

ユーザー入力を実行する可能性のあるコンテキストでこれらの機能を許可することはセキュリティの問題であり、実際に機能するサニタイザーを作成するのは困難です。

于 2009-12-19T17:01:40.310 に答える
5

rootとしてログインしてはいけないのと同じ理由:足を撃ち抜くのは簡単すぎます。

于 2009-12-19T17:02:46.877 に答える
4

コンピューターで次のことを実行しようとしないでください。

s = "import shutil; shutil.rmtree('/nonexisting')"
eval(s)

たとえば、誰かがWebアプリケーションからを制御できると仮定します。

于 2009-12-19T17:01:51.500 に答える
3

理由#1:1つのセキュリティ上の欠陥(つまり、プログラミングエラー...そしてそれらを回避できるとは言えません)と、サーバーのシェルへのアクセスをユーザーに与えたところです。

于 2009-12-19T17:03:15.007 に答える
3

対話型インタープリターでこれを試して、何が起こるか見てみましょう:

>>> import sys
>>> eval('{"name" : %s}' % ("sys.exit(1)"))

もちろん、これはまれなケースですが、このような事態を防ぐのは難しい場合があります。

于 2009-12-19T17:08:22.837 に答える