88

私が PHP で開発してきたすべての年で、私は常に PHP を使用することeval()は悪であると聞いてきました。

次のコードを考えると、2 番目の (そしてより洗練された) オプションを使用するのは理にかなっているのではないでしょうか? そうでない場合、なぜですか?

// $type is the result of an SQL statement, e.g.
// SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string.

$type = "enum('a','b','c')";

// option one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);

// option two
eval('$result = '.preg_replace('#^enum#','array', $type).';');
4

20 に答える 20

135

eval() を純粋な悪と呼ぶことには注意が必要です。動的評価は強力なツールであり、命の恩人になることもあります。eval() を使用すると、PHP の欠点を回避できます (以下を参照)。

eval() の主な問題は次のとおりです。

  • 安全でない入力の可能性。信頼されていないパラメーターを渡すと、失敗する可能性があります。多くの場合、パラメーター (またはその一部) が完全に信頼されていることを確認するのは簡単な作業ではありません。
  • トリッキーさ。eval() を使用するとコードが賢くなり、従うのが難しくなります。Brian Kernighan の言葉を引用すると、「デバッグは、最初からコードを書くよりも 2 倍難しい。したがって、コードをできる限り賢く書いたとしても、定義上、それをデバッグできるほど頭が良くないということになる

eval() の実際の使用に関する主な問題は 1 つだけです。

  • 十分に考慮せずに使用する経験の浅い開発者。

経験則として、私はこれに従う傾向があります:

  1. eval() が唯一の/正しい解決策である場合があります。
  2. ほとんどの場合、別の方法を試す必要があります。
  3. 不明な場合は、2 に進みます。
  4. それ以外の場合は、非常に注意してください。
于 2009-06-04T17:08:24.517 に答える
42

評価された文字列に userinput が含まれる可能性がごくわずかしかない場合、 eval は悪です。ユーザーからのコンテンツなしで eval を実行する場合、安全である必要があります。

それにもかかわらず、eval を使用する前に少なくとも 2 回考える必要があります。一見単純に見えますが、エラー処理 (VBAssassins のコメントを参照)、デバッグ可能性などを考慮すると、それほど単純ではありません。

経験則として、忘れてください。eval が答えの場合、おそらく間違った質問をしています! ;-)

于 2009-06-04T15:47:52.923 に答える
19

eval は常に等しく「悪」です。

あなたがそれを悪と見なすなら、それは常に同じように悪です。多くの人がそれを悪と表現する理由は、文脈によって消えません。

eval() を使用すると、コードの可読性が低下し、実行前にコード パスを予測する能力が損なわれ (セキュリティに影響する可能性があります)、コードを分析およびデバッグする能力に影響するため、一般的には悪い考えです。eval() を使用すると、評価されたコードとその周囲のコードが、PHP 5.5 以降に統合された Zend Opcache などのオペコード キャッシュや、HHVM のような JIT コンパイラによって最適化されるのを防ぐこともできます。

さらに、eval() を使用することが絶対に必要な状況はありません。PHP は、eval() がなくても十分に機能するプログラミング言語です。eval() を何に使用するかに関係なく、PHP でそれを行う別の方法があります。

これらを実際に悪と見なすかどうか、または eval() を使用して個人的に正当化できるかどうかは、あなた次第です。落とし穴が大きすぎて正当化できない人もいれば、 eval() が便利なショートカットである人もいます。

于 2009-06-05T01:36:37.000 に答える
15

この場合、ユーザーがテーブルに任意の列を作成することが不可能である限り、evalはおそらく十分に安全です。

しかし、それは実際にはこれ以上エレガントではありません。これは基本的にテキスト解析の問題であり、PHPのパーサーを悪用して処理するのは少しハッキーなようです。言語機能を悪用したい場合は、JSONパーサーを悪用してみませんか?少なくともJSONパーサーでは、コードインジェクションの可能性はまったくありません。

$json = str_replace(array(
    'enum', '(', ')', "'"), array)
    '',     '[', ']', "'"), $type);
$result = json_decode($json);

正規表現はおそらく最も明白な方法です。単一の正規表現を使用して、この文字列からすべての値を抽出できます。

$extract_regex = '/
    (?<=,|enum\()   # Match strings that follow either a comma, or the string "enum("...
    \'      # ...then the opening quote mark...
    (.*?)       # ...and capture anything...
    \'      # ...up to the closing quote mark...
    /x';
preg_match_all($extract_regex, $type, $matches);
$result = $matches[1];
于 2009-06-04T16:21:19.317 に答える
14

eval()遅いですが、私はそれを悪とは呼びません。

コードインジェクションにつながり、悪になる可能性があるのは、私たちの悪い使い方です。

簡単な例:

$_GET = 'echo 5 + 5 * 2;';
eval($_GET); // 15

有害な例:

$_GET = 'system("reboot");';
eval($_GET); // oops

使用しないことをお勧めしますが、使用するeval()場合は、すべての入力を検証/ホワイトリストに登録してください。

于 2010-01-14T02:36:04.450 に答える
12

eval 内で外部データ (ユーザー入力など) を使用している場合。

上記の例では、これは問題ではありません。

于 2009-06-04T15:46:50.773 に答える
7

ここでコンテンツを露骨に盗みます:

  1. Eval はその性質上、常にセキュリティ上の懸念事項になります。

  2. セキュリティ上の懸念に加えて、 eval には信じられないほど遅いという問題もあります。PHP 4.3.10 での私のテストでは、通常のコードよりも 10 倍遅く、PHP 5.1 beta1 では 28 倍遅くなりました。

blog.joshuaeichorn.com: using-eval-in-php

于 2009-06-04T16:51:01.823 に答える
5

eval()常に悪です。

  • セキュリティ上の理由から
  • パフォーマンス上の理由から
  • 読みやすさ/再利用性の理由から
  • IDE/ツールの理由
  • デバッグの理由で
  • 常により良い方法があります
于 2013-01-31T13:50:07.560 に答える
4

個人的には、コードが何をしているのかコメントしていないので、コードはまだかなり邪悪だと思います。また、入力の有効性をテストしていないため、非常に脆弱です。

また、evalの使用の95%(またはそれ以上)は積極的に危険であるため、他の場合に提供される可能性のあるわずかな時間の節約は、それを使用するという悪い習慣にふける価値がないと感じています。さらに、後で、評価の使用が良い理由と悪い理由をミニオンに説明する必要があります。

そしてもちろん、PHPはPerlのように見えてしまいます;)

eval()には2つの重要な問題があります(「インジェクション攻撃」シナリオとして)。

1)害を及ぼす可能性があります2)単にクラッシュする可能性があります

そして、技術的というよりも社会的であるもの:

3)他の場所でのショートカットとして不適切に使用するように人々を誘惑します

最初のケースでは、任意のコードが実行されるリスクがあります(明らかに、既知の文字列を評価しているときではありません)。ただし、入力は、思ったほど知られていないか、固定されていない可能性があります。

より可能性が高いのは(この場合)クラッシュするだけで、文字列は不当にあいまいなエラーメッセージで終了します。私見ですが、すべてのコードは可能な限りきちんと失敗し、失敗すると例外がスローされます(最も処理しやすい形式のエラーとして)。

この例では、動作に合わせてコーディングするのではなく、偶然にコーディングしていることをお勧めします。はい、SQL列挙型ステートメント(そして、そのフィールドの列挙型は確かですか?-データベースの適切なバージョンの適切なテーブルの適切なフィールドを呼び出しましたか?実際に答えましたか?)は、PHPの配列宣言構文のように見えます。しかし、あなたが本当にやりたいことは、入力から出力への最短経路を見つけることではなく、指定されたタスクに取り組むことをお勧めします。

  • 列挙型があることを確認します
  • 内部リストを抽出する
  • リスト値を解凍します

これはおおよそあなたのオプションの1つですが、明確さと安全性のために、ifとコメントをいくつかラップします(たとえば、最初の一致が一致しない場合は、例外をスローするか、nullの結果を設定します)。

エスケープされたコンマまたは引用符にはまだいくつかの問題が考えられます。おそらくデータを解凍してから引用符を外す必要がありますが、少なくともデータをコードではなくデータとして扱います。

preg_versionを使用すると、最悪の結果は$ result = nullになる可能性が高く、evalバージョンを使用すると、最悪の結果は不明ですが、少なくともクラッシュします。

于 2009-06-04T16:19:59.070 に答える
4

また、あなたのコードを保守している人々にも配慮します。

eval() を見て、何が起こるのかを知るのは簡単ではありません。あなたの例はそれほど悪くはありませんが、他の場所では悪夢になる可能性があります。

于 2009-06-04T16:00:30.163 に答える
3

PHP では、明示的な評価を行う代わりに、call_user_func を介して実行できるようにコードを記述することをお勧めします。

于 2009-06-05T01:13:44.893 に答える
3

eval は文字列をコードとして評価します。問題は、文字列が何らかの形で「汚染されている」場合、巨大なセキュリティ上の脅威にさらされる可能性があることです。通常、問題はユーザー入力が文字列で評価される場合です。多くの場合、ユーザーはコード (php または ssi など) を入力して eval 内で実行できます。それは、php スクリプトと同じ権限で実行され、サーバーへの情報/アクセスを取得するために使用されます。ユーザー入力が eval に渡される前に適切に消去されていることを確認するのは非常に難しい場合があります。他にも問題があります...そのうちのいくつかは議論の余地があります

于 2009-06-04T16:24:00.190 に答える
2

もう 1 つのeval悪い理由は、eAccelertor や ACP などの PHP バイトコード キャッシュによってキャッシュできなかったことです。

于 2010-01-14T04:00:45.713 に答える
2

関数ではなく、 eval() を悪にするのは悪いプログラミングです。複数のサイトでの動的プログラミングでは回避できないため、時々使用します。必要なものを受け取ることができないため、PHP を 1 つのサイトで解析することはできません。私は結果を受け取るだけです!eval() のような関数が存在することをうれしく思います。ユーザー入力?ハッカーに引っかかるのは、悪いプログラマーだけです。私はそれについて心配していません。

すぐに深刻な問題が発生すると予測しています...

正直なところ、PHP などのインタープリター型言語では、eval などの法外な関数を適切に使用することはまったくありません。他のより安全な方法を使用して実行できなかった eval がプログラム関数を実行するのを見たことがありません...

Eval はすべての悪の根源であり、ユーザー入力のテストが役立つと考えるすべての人々に心から同意します。考え直してください。ユーザー入力はさまざまな形式で提供される可能性があり、私たちが話しているように、ハッカーはあなたが十分に気にかけなかったその機能を悪用しています。私の意見では、 eval を完全に避けてください。

私自身の創造性を超えた eval 関数を悪用する巧妙な例を見てきました。セキュリティの観点からは、絶対に避けてください。「与えられた」ものではなく、少なくとも PHP 構成のオプションであることを要求することさえあります。

于 2011-05-26T15:00:02.173 に答える
2

関数ではなく、 eval() を悪にするのは悪いプログラミングです。複数のサイトでの動的プログラミングでは回避できないため、時々使用します。必要なものを受け取ることができないため、PHP を 1 つのサイトで解析することはできません。私は結果を受け取るだけです!eval() のような関数が存在することをうれしく思います。ユーザー入力?ハッカーに引っかかるのは、悪いプログラマーだけです。私はそれについて心配していません。

于 2011-02-27T12:29:27.357 に答える
1

以前は eval() をよく使用していましたが、ほとんどの場合、eval を使用してトリックを実行する必要はありません。さて、PHP には call_user_func() と call_user_func_array() があります。任意のメソッドを静的および動的に呼び出すだけで十分です。

静的呼び出しを実行するには、コールバックを array('class_name', 'method_name') または 'class_name::method_name' のような単純な文字列として構築します。動的呼び出しを実行するには、array($object, 'method') スタイルのコールバックを使用します。

eval() の唯一の賢明な使用法は、カスタム コンパイラを作成することです。私はそれを作成しましたが、デバッグが非常に難しいため、eval は依然として悪です。最悪の事態は、評価されたコードの致命的なエラーが、それを呼び出したコードをクラッシュさせることです。私はParsekit PECL拡張機能を使用して、少なくとも構文をチェックしましたが、まだ喜びはありません.不明なクラスとアプリ全体のクラッシュを参照してみてください.

于 2010-01-14T01:56:17.440 に答える
0

セキュリティ上の懸念を除けば、eval()はコンパイル、最適化、またはオペコードのキャッシュができないため、通常のphpコードよりも常に遅くなります。したがって、evalを使用することはパフォーマンスに影響しませんが、それが悪になることはありません。(goto悪でevalあり、悪い習慣/臭いコード/醜いだけです)

于 2012-06-29T01:59:13.670 に答える