JavaScriptのeval()が悪ではないのはいつですか?


263

(スプレッドシートのような機能のために)ユーザーが入力した関数を解析するJavaScriptコードを書いています。私は式解析された可能性はJavaScriptに変換して実行しeval()、結果を得るために、その上に。

しかし、私はeval()それが悪であるのでそれを避けることができる場合は常に使用を避けてきました(そして、正しいかまたは間違って、評価されるコードはユーザーによって変更される可能性があるため、JavaScriptではさらに悪であると常に思っていました)。

それで、いつそれを使用してもよいですか?


5
ほとんどのJSONライブラリは、実際にはセキュリティリスクから保護するために内部でevalを使用していません。
Sean McMillan、

11
@Sean-JQueryとプロトタイプの両方がevalを使用します(JQueryは新しい関数を介してそれを使用します)
プロダー2010

5
@plodder-どこで情報を入手していますか?jQueryは、1.4からネイティブJSON.parse()を利用しています(1/2010に遡ります)!自分の目で確かめ
ケン

3
「明らかに、JSONを解析するためにeval()を使用する必要があります」 -逆に、これは真実ではありません-JSONを解析するためにevalを使用すべきではありません!json.orgからのDouglas Crockfords(JSONの作成者)json2.jsスクリプトを使用してください
TMS

11
@Tomas皮肉なことに、json2.jsはevalを使用してJSONを解析しています
tobyodavies

回答:


262

私はあなたの質問の前提に対処するために少し時間をとりたいと思います-eval()は「」です。プログラミング言語の人々が使用する「」という言葉は、通常「危険」、またはより正確には「単純に見えるコマンドで多くの害を及ぼす可能性がある」を意味します。では、危険なものを使用してもよいのはいつですか。危険が何であるかを知り、適切な予防策を講じているとき。

要点として、eval()の使用における危険性を見てみましょう。おそらく他のすべてと同じように小さな隠れた危険がたくさんあるでしょうが、2つの大きなリスク-eval()が悪と見なされる理由-はパフォーマンスとコードインジェクションです。

  • パフォーマンス-eval()はインタープリター/コンパイラーを実行します。コードがコンパイルされている場合、ランタイムの途中で重い可能性のあるコンパイラを呼び出す必要があるため、これは大ヒットです。ただし、JavaScriptは依然としてほとんどの場合インタプリタ言語です。つまり、eval()を呼び出しても、一般的なケースではパフォーマンスに大きな影響はありません(ただし、以下の具体的なコメントを参照してください)。
  • コードインジェクション-eval()は、昇格された特権でコード文字列を実行する可能性があります。たとえば、administrator / rootとして実行されているプログラムは、ユーザー入力を「rm -rf / etc / important-file」またはそれよりも悪い可能性があるため、eval()ユーザー入力を望まないでしょう。この場合も、プログラムはユーザー自身のアカウントで実行されているため、ブラウザーのJavaScriptにはそのような問題はありません。サーバー側のJavaScriptがその問題を抱えている可能性があります。

あなたの特定のケースに移ります。私が理解していることから、あなたは自分で文字列を生成しているので、「rm -rf something-important」のような文字列が生成されないように注意すると、コードインジェクションのリスクはありません(ただし、非常に非常に重要です)一般的なケースではこれを確実にすることは困難です)。また、ブラウザーで実行している場合、コードインジェクションはかなり小さなリスクであると私は信じています。

パフォーマンスに関しては、コーディングの容易さに対して重み付けする必要があります。式を解析する場合、別のパーサー(eval()内のパーサー)を実行するのではなく、解析中に結果を計算することもできます。しかし、eval()を使用してコーディングする方が簡単な場合があり、パフォーマンスへの影響はおそらく目立ちません。この場合のeval()は、時間を節約できる可能性のある他のどの関数よりも邪悪ではないようです。


78
デバッグが難しいevalを使用するコードの問題に対処していません
bobobobo 09

48
コードインジェクションは、ユーザーデータにまったく関心がある場合、JavaScriptの非常に深刻な問題です。挿入されたコードは、ブラウザから、あたかもあなたのサイトから来たかのように実行され、ユーザーが手動で実行できるあらゆる種類の不正行為を可能にします。(サードパーティの)コードによるページへのアクセスを許可すると、顧客に代わって注文したり、顧客の墓場を変更したり、サイトでできることを何でも行うことができます。十分気をつける。ハッカーが顧客を所有できるようにすることは、サーバーを所有できるようにするのと同じくらい悪いことです。
ショーン・マクミラン、

71
サーバーからのデータと、開発者が生成したそのデータの場合、eval()を使用しても害はありません。本当の害はあなたが読んだすべてのものを信じることです。eval()は悪だと言っている人がたくさんいますが、どこかで読んだことを除いて、彼らはなぜそれを理解していません。
Vince Panuccio

42
@Sean McMillan:私はあなたを信じたいのですが、誰かがeval()あなたのサーバーから行くjavascriptを傍受して変更しようとする場合、彼らはそもそもページのソースを変更し、ユーザーの情報を制御することもできます。。。違いはわかりません。
Walt W

20
「コードインジェクション-...繰り返しになりますが、ブラウザのJavaScriptにはその問題はありません」&「また、ブラウザで実行している場合、コードインジェクションはかなり小さなリスクであると私は信じています。」ブラウザでのコードインジェクションは問題ではないことを示唆していますか?XSSは、OWASPのトップ10リストで数年前からトップ3の脆弱性にランクされています。
マイクサミュエル

72

eval()悪ではありません。あるいは、そうであれば、リフレクション、ファイル/ネットワークI / O、スレッド化、IPCが他の言語で「悪」であるのと同じ方法で悪です。

、場合あなたの目的のためにeval()手動の解釈よりも高速である、またはあなたのコードは単純で、またはより明確になります...そして、あなたはそれを使用する必要があります。どちらでもない場合は、すべきではありません。そのような単純な。


5
そのような目的の1つは、手作業で書くには長すぎたり反復が多すぎたりする最適化されたコードを生成することです。LISPでマクロを必要とするようなもの。
wberry 14年

5
これは非常に一般的なアドバイスなので、文字通り存在するコードブロックに適用できます。実際には、この質問には何も追加されません。特に、ここに来た人が特定の使用法に問題があるかどうかを判断するのに役立ちません。
jpmc26

2
より速く、よりシンプルで、より明確に...この回答は、セキュリティへの影響を十分にカバーしていません。
Ruud Helderman

55

ソースを信頼するとき。

JSONの場合、ソースを改ざんすることは多かれ少なかれ困難です。なぜなら、それが制御するWebサーバーからのものだからです。JSON自体にユーザーがアップロードしたデータが含まれていない限り、evalを使用しても大きな欠点はありません。

他のすべての場合では、eval()に供給する前に、ユーザーが指定したデータが私のルールに準拠するように最大限の努力をします。


13
json文字列は、eval()で使用する前に、常にjson文法に対してテストする必要があります。したがって、「alert( 'XSS')」は適切な値ではないため、json文字列「{foo:alert( 'XSS')}」は渡されません。
ガンボ

3
では、HTTPSを使用してください。OTOH:man-in-the-middleは、ガーデンのさまざまなWebアプリの典型的な攻撃シナリオではありませんが、クロスサイトスクリプティングはそうです。
Tomalak 2009

7
evalまた、すべての有効なJSON文字列を正しく解析しません。例えばJSON.parse(' "\u2028" ') === "\u2028"しかし、eval(' "\u2028" ')U + 2028は、JavaScriptで改行ですが、それは限りJSONに関しては改行ではないので、例外が発生します。
マイクサミュエル

1
@Justin-プロトコルが危険にさらされている場合、通常、最初のページの読み込みは同じプロトコルを介して送信され、クライアントはすでに可能な限り危険にさらされているため、それは問題点です。
アンチノーム2013年

1
美しく@Tomalakと言いました、私は今私の答えでこれを述べました!驚くばかり!
NiCkニューマン

25

本当の人々を手に入れましょう:

  1. すべての主要なブラウザーには、組み込みのコンソールがあり、ハッカーになる可能性のあるユーザーが豊富な機能を使用して、任意の値を持つ任意の関数を呼び出すことができます。

  2. JavaScriptの2000行をコンパイルするのに0.2秒かかる場合、4行のJSONを評価すると、パフォーマンスはどのように低下​​しますか?

「eval is evil」についてのクロックフォードの説明でさえ弱い。

evalは悪であり、eval関数はJavaScriptの最も誤用されている機能です。それを避ける

クロックフォード自身が言うかもしれないように「この種の声明は不合理な神経症を引き起こす傾向がある。それを買わないでください」。

evalを理解し、いつ役立つかを知ることは、さらに重要です。たとえば、evalは、ソフトウェアによって生成されたサーバー応答を評価するための賢明なツールです。

ところで:Prototype.jsはevalを5回直接呼び出します(evalJSON()とevalResponse()を含む)。jQueryはそれをparseJSONで(関数コンストラクターを介して)使用します。


10
JQueryはブラウザーの組み込みJSON.parse関数を使用します(使用可能な場合ははるかに高速で安全です)。フォールバックメカニズムとしてのみevalを使用します。「eval is evil」という文はかなり良いガイドラインです。
jjmontes

30
Re「すべての主要なブラウザにコンソールが組み込まれています...」。コードインジェクションは、あるユーザーがコードを入力して、別のユーザーのブラウザーで実行できる場合の問題です。ブラウザーコンソール自体では、1人のユーザーが別のユーザーのブラウザーでコードを実行することはできません。そのため、コードインジェクションから保護する価値があるかどうかを判断する際には関係ありません。
マイクサミュエル

28
「すべての主要なブラウザには現在コンソールが組み込まれています...なぜevalステートメントを使用する必要があるのですか?」-あなたはマークからかなり外れています。答えを編集することをお勧めします。あるユーザーが別のユーザーのブラウザーで実行できるコードを挿入できるかどうかが大きな問題です。そして、これはあなたが本当に現実になるために必要な場所です。
akkishore

5
@akkishore、あなたの過剰な発言をサポートする実際の例を考えていただければ幸いです。
Akash Kava 2013

7
@AkashKava気づいていないのは、コメントボックスにJavaScriptを送信すると、そのJavaScriptがデータベースに送信されるということです。別のユーザーがそのコメント(私がJavaScriptを入れたもの)を表示すると、evalはレンダリング時にそのJavaScriptを取得し、インタープリターを使用して評価するため、埋め込みJavaScriptが他のユーザーのブラウザーで実行されます。そうすることで、いろいろな情報を収集することができます。ユーザー名、データベース内のユーザーID、電子メールアドレスなど。これは難しい答えではありません。GoogledXSSを使用している場合は、約10秒で問題の原因がわかります。
カイルリヒター

18

私は従う傾向クロックフォードのアドバイスのためにeval()、そして完全にそれを避けます。それを必要とするように見える方法でさえもそうではありません。たとえば、setTimeout()ではevalではなく関数を渡すことができます。

setTimeout(function() {
  alert('hi');
}, 1000);

信頼できるソースであるとしても、JSONから返されたコードが文字化けしている可能性があるため、私はそれを使用していません。


2
サーバー側のJSONフォーマッターのバグは確かに問題だと思います。サーバーからの応答は、ユーザーが送信したテキストの種類に依存しますか?次に、XSSを監視する必要があります。
swilliams 2008年

3
WebサーバーがHTTPS経由で認証されていない場合、別のホストがリクエストを傍受して独自のデータを送信する、ある種の中間者攻撃を受ける可能性があります。
ベンコンビー2008

11
誰かが中間者攻撃を実行できる場合、スクリプトに何でも簡単に挿入できます。
el.pescado

10
JavaScriptコードにまったく依存するべきではありません...クライアント側で実行されるものに依存するべきではありません...誰かが中間者攻撃を行った場合、なぜ彼はあなたのjsonオブジェクトをいじくりますか?彼はあなたと別のjsファイルに別のウェブページを提供できます...
Calmarius

5
私は個人的に、「それを行うには常に他の方法がある」という主張を嫌っています。たとえば、オブジェクト指向プログラミングを回避する方法は常にあると言えます。それはそれが素晴らしいオプションではないという意味ではありません。evalとその危険を理解している場合、それは適切な状況で使用するための優れたツールとなります。
ダリン

4

evilevilであるため、evalを使用しないことを推奨しているのを見ましたが、同じ人がFunctionとsetTimeoutを動的に使用しているため、内部 evalを使用しているのがわかりました

ところで、サンドボックスが十分に明確でない場合(たとえば、コードインジェクションを許可するサイトで作業している場合)、evalは最後の問題です。セキュリティの基本的なルールがあることである、すべての入力が悪であるが、JavaScriptの場合にも、 JavaScriptであなたが任意の関数を上書きすることができますし、あなただけの、そう、あなたが本当のものを使用していることを確認することはできませんので、JavaScriptの自体は、悪の可能性悪意のあるコードがあなたの前に始まる場合、JavaScript組み込み関数を信頼することはできません:D

この投稿のエピローグは次のとおりです。

あなたがいる場合本当にそれを必要とする(時間のevalの80%がされないで必要)と、ちょうど使用evalをやって再何」は、あなたがしていることを確認(またはより良い機能を;))、閉鎖やOOPは、80/90%をカバー別の種類のロジックを使用してevalを置き換えることができる場合、残りは動的に生成されたコード(たとえば、インタープリターを作成している場合)であり、JSONの評価についてすでに述べたように(ここではCrockfordの安全な評価を使用できます;))


また、Crockford自身が指摘したように、現在のWebブラウザーには組み込み関数JSON.parseがあります。
Ruud Helderman、

4

Evalは、コードのテンプレート化に使用されるコンパイルを補完します。テンプレート化とは、開発速度を向上させる便利なテンプレートコードを生成する簡略化されたテンプレートジェネレータを作成することを意味します。

開発者がEVALを使用しないフレームワークを作成しましたが、開発者は私たちのフレームワークを使用しているため、そのフレームワークはテンプレートを生成するためにEVALを使用する必要があります。

EVALのパフォーマンスは、次の方法を使用して向上させることができます。スクリプトを実行する代わりに、関数を返す必要があります。

var a = eval("3 + 5");

次のように構成する必要があります

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

fをキャッシュすると速度が向上します。

また、Chromeでは、このような機能のデバッグを非常に簡単に行うことができます。

セキュリティに関しては、evalを使用してもしなくてもかまいません。

  1. まず、ブラウザはサンドボックスでスクリプト全体を呼び出します。
  2. EVALで悪であるコードはすべて、ブラウザ自体で悪です。攻撃者または誰でも、DOMにスクリプトノードを簡単に挿入し、評価できる場合は何でもできます。EVALを使用しなくても違いはありません。
  3. 有害なのは、ほとんどの場合サーバー側のセキュリティが低いことです。サーバーでのCookie検証が不十分であるか、ACLの実装が不十分であると、ほとんどの攻撃が発生します。
  4. 最近のJavaの脆弱性などがJavaのネイティブコードにありました。JavaScriptはサンドボックスで実行するように設計されていますが、アプレットは脆弱性やその他多くの原因となる証明書などを使用してサンドボックスの外部で実行するように設計されています。
  5. ブラウザを模倣するためのコードを書くことは難しくありません。必要なのは、お気に入りのユーザーエージェント文字列を使用してサーバーにHTTP要求を行うことだけです。いずれにしても、すべてのテストツールはブラウザを模擬します。攻撃者があなたを傷つけたい場合、EVALは最後の手段です。サーバー側のセキュリティに対処する方法は他にもたくさんあります。
  6. ブラウザーDOMは、ユーザー名ではなく、ファイルへのアクセス権を持っていません。実際、evalがアクセス権を付与できるマシンには何もありません。

サーバー側のセキュリティが誰でもどこからでも攻撃できるほど強固であれば、EVALについて心配する必要はありません。前述したように、EVALが存在しない場合、攻撃者はブラウザのEVAL機能に関係なく、サーバーにハッキングするための多くのツールを持っています。

Evalは、事前に使用されていないものに基づいて複雑な文字列処理を行うテンプレートを生成する場合にのみ適しています。たとえば、私は好みます

"FirstName + ' ' + LastName"

とは対照的に

"LastName + ' ' + FirstName"

私の表示名として、これはデータベースから取得でき、ハードコーディングされていません。


eval-の代わりにfunctionを使用できますfunction (first, last) { return last + ' ' + first }
Konrad Borowski 2013年

列の名前はデータベースから取得されます。
Akash Kava 2013年

3
の脅威evalは主に他のユーザーです。たとえば、設定ページがあり、自分の名前が他の人にどのように表示されるかを設定できるとします。また、書いたときにあまりよく考えていなかったため、選択ボックスにのようなオプションがあるとします<option value="LastName + ' ' + FirstName">Last First</option>。開発ツールを開き、valueオプションのをに変更し、変更したオプションをalert('PWNED!')選択して、フォームを送信します。これで、他の人が私の表示名を見ることができるときはいつでも、そのコードが実行されます。
cHao

@cHao、あなたが話しているのは貧弱なサーバー側のセキュリティの例です、サーバーは誰のブラウザでもコードとして実行できるデータを決して受け入れてはいけません。ここでも、サーバー側のセキュリティが不十分であるという概念を理解できていません。
Akash Kava

1
必要に応じて、サーバー側のセキュリティについて愚痴を言うこともできますが、全体のポイントevalは、作成したスクリプトの一部ではないコードを実行することです。それを行う力が必要ない場合(そしてほとんど必要ない場合)、回避evalすることで問題のカテゴリ全体を回避できます。サーバー側のコードが完全ではない場合、これは良いことです。
cHao

4

Chrome(v28.0.1500.72)でデバッグするとき、クロージャーを生成するネストされた関数で使用されていない変数はクロージャーにバインドされていないことがわかりました。それはJavaScriptエンジンの最適化だと思います。

BUTeval()クロージャを引き起こす関数内で使用される場合、外部関数のすべての変数は、たとえそれらがまったく使用されなくても、クロージャにバインドされます。それによってメモリリークが発生する可能性があるかどうかをテストする時間があれば、コメントを残してください。

これが私のテストコードです:

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

ここで指摘したいのは、eval()は必ずしもネイティブeval()関数を参照する必要はないということです。それはすべて関数の名前に依存します。したがってeval()、エイリアスを使用して(たとえばvar noval = eval;、内部関数でnoval(expression);)ネイティブを呼び出すexpressionと、クロージャの一部であるはずの変数を参照するときに、の評価が失敗することがありますが、実際にはそうではありません。



3

ボトムライン

あなたが自分でコードを作成またはサニタイズした場合eval、それが悪になることはありません。

やや詳細

evalある邪悪されたクライアントから提出された入力を使用してサーバー上で実行されている場合は、開発者によって作成されていないか、された開発者によってサニタイズありません

evalクライアントで作成された無害化されていない入力を使用しても、クライアントで実行している場合は問題ありません

明らかに、コードが消費するものをある程度制御するために、常に入力を無害化する必要があります。

推論

クライアントは、開発者がコーディングしていない場合でも、必要な任意のコードを実行できます。これは、評価されたものだけでなく、それ自体eval呼びかけに当てはまります


2

eval()を使用する必要がある唯一の例は、動的JSをその場で実行する必要がある場合です。私はあなたがサーバーから非同期でダウンロードするJSについて話している...

...そして10回のうち9回は、リファクタリングによって簡単に回避できます。


現在、サーバーからJavaScriptを非同期でロードする方法は他にも(より良い)あります。w3bits.com
Ruud Helderman

1

evalめったに正しい選択ではありません。スクリプトを連結してその場で実行することにより、達成する必要があることを達成できる多くのインスタンスがあるかもしれませんが、通常は、より強力で保守可能なテクニックを自由に使用できます。連想配列表記(obj["prop"]と同じですobj.prop) 、クロージャ、オブジェクト指向テクニック、関数テクニック-代わりにそれらを使用してください。


1

クライアントスクリプトに関する限り、セキュリティの問題は議論の余地があると思います。ブラウザに読み込まれるものはすべて操作の対象となるため、そのように扱う必要があります。ブラウザのURLバーなど、JavaScriptコードを実行したり、DOM内のオブジェクトを操作したりする方法がはるかに簡単な場合、eval()ステートメントを使用してもリスクはありません。

javascript:alert("hello");

誰かが自分のDOMを操作したい場合、私は振り向かないと言います。あらゆる種類の攻撃を防ぐためのセキュリティは、常にサーバーアプリケーションの責任です。

実用的な観点からは、他の方法で実行できる状況でeval()を使用するメリットはありません。ただし、evalを使用する必要がある特定のケースがあります。その場合、ページを爆破するリスクなしに確実に実行できます。

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

6
「JavaScriptを実行したり、DOMでオブジェクトを操作したりする方法がはるかに簡単な場合、eval()ステートメントを使用してもリスクはありません」コードインジェクションは、あるユーザーがコードを入力して、別のユーザーのブラウザーで実行できる場合の問題です。ブラウザーコンソール自体では、1人のユーザーが別のユーザーのブラウザーでコードを実行することはできません。そのため、コードインジェクションから保護する価値があるかどうかを判断する際には関係ありません。
マイクサミュエル

<head></head>空であっても必要ありませんか?
Peter Mortensen

2
この回答は、XSSのリスクを完全に無視しています。
Ruud Helderman

1

サーバー側では、sql、influxdb、mongoなどの外部スクリプトを処理するときにevalが役立ちます。サービスを再デプロイせずに、実行時にカスタム検証を行うことができる場所。

たとえば、次のメタデータを持つ達成サービス

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

許可すると、

  • jsonのリテラル文字列を介したオブジェクト/値の直接注入。テキストのテンプレート化に役立ちます

  • コンパレーターとして使用できます。CMSでクエストまたはイベントを検証する方法をルール化するとします

これの欠点:

  • 完全にテストされていない場合、コードのエラーが発生し、サービスの問題が解消される可能性があります。

  • ハッカーがシステムにスクリプトを書くことができる場合、あなたはかなりめちゃくちゃです。

  • スクリプトを検証する1つの方法は、スクリプトのハッシュを安全な場所に保管して、実行前にチェックできるようにすることです。


いいね。私が質問したとき、サーバー側のJSについてさえ考えていませんでした。
リチャードターナー

1

evalが正当化されるケースはほとんどないと思います。実際に正当化されているときに使用するよりも、正当化されていると考えて使用する可能性が高くなります。

セキュリティの問題は最もよく知られています。ただし、JavaScriptはJITコンパイルを使用しており、これはevalとの連携が不十分であることにも注意してください。Evalはコンパイラにとってブラックボックスのようなもので、パフォーマンスの最適化とスコープを安全かつ正確に適用するには、JavaScriptがコードを事前に(ある程度)予測できる必要があります。場合によっては、パフォーマンスへの影響がeval以外の他のコードに影響を与えることさえあります。

詳細を知りたい場合:https : //github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval


0

eval関数に渡されるコードを完全に制御できる場合は、これを使用しても問題ありません。


2
渡す対象を完全に制御している場合eval、大きな疑問が生じます。それが本当のJSではなく文字列であることがいつ意味をなすのでしょうか。
cHao

@cHaoたとえば、大きなゲームアプリケーション(5-10MBのJavascript)がある場合は、最初に、大きなメインスクリプトをロードする一方で、ロード中のバーまたは類似のもの。ダウンロード後、「eval(source)」またはより優れた「new Function(source)」を使用して、ロードされたGame-Application-Scriptを実行できます。これにより、ユーザーはアプリケーションがゲームを開始するまでダウンロードに時間がかかることを視覚的に確認できます。それがなければ、ユーザーは視覚的なフィードバックなしでアプリケーション全体がロードされるのを待つ必要があります。
SammieFox 2017

@SammieFoxこれを行うには他の(そしてより良い)方法があります<script async="true" src="...">。参照:w3bits.com/async-javascript
Ruud Helderman

答えは危険なアドバイスです。あまりにも多くの開発者がコントロールしているという誤った感覚を持っています。アドバイスはありません、もはや積極的に維持されているソフトウェアのためのいくつかの意味をなします。しかし、そのようなソフトウェアは死んでいると考えるべきです。
Ruud Helderman、

0

可能であれば、テスト中のみ。また、eval()は他の特殊なJSONなどのエバリュエーターよりもはるかに遅いことに注意してください。


0

コードのソースが自分または実際のユーザーからのものであることを確認できる限り、eval()を使用しない理由はありません。彼はeval()関数に送信されるものを操作できますが、Webサイトのソースコードを操作できるため、JavaScriptコード自体を変更できるため、セキュリティ上の問題ではありません。

だから... eval()を使用しないのはいつですか?Eval()は、第三者が変更する可能性がある場合にのみ使用してはなりません。クライアントとサーバー間の接続を傍受するようなものです(ただし、それが問題である場合はHTTPSを使用してください)。フォーラムのように他の人が書いたコードを解析するためにeval()を使うべきではありません。


「コードのソースがあなたまたは実際のユーザーからのものであることを確認できる限り、eval()を使用しない理由はありません。」これは、単一のユーザーがいることを前提としています。その前提はOPに記載されていません。複数のユーザーがいる場合eval、1人のユーザーのコンテンツから構成される文字列を不注意にすると、そのユーザーは他のユーザーのブラウザーでコードを実行できるようになります。
マイクサミュエル

@ MikeSamuel、evalは他のユーザーのブラウザーでコードを実行できます。これは聞いたことがありません。これを試しましたか?これはブラウジングの歴史では決して起こらなかったのですが、例を示していただけますか?
Akash Kava 2013

@AkashKava、文字列は1つのユーザーエージェントで生成され、データベースに格納され、それを使用する別のブラウザに提供されますeval。それはいつも起こります。
マイクサミュエル

@MikeSamuelデータベース?どこ?誰が間違った文字列を提供しますか?それはサーバー側のデータベースのせいではありませんか?まず第一に、EVALは、不十分に記述されたサーバー側コードに対して非難されるべきではありません。jsfiddleを使用して、害を及ぼす可能性のある実際の例を世界に示します。
Akash Kava 2013

2
@AkashKava、私はあなたの質問を理解していません。特定のアプリケーションについて話しているのではありませんが、を使用しない理由evalです。サーバーのせいにすることはどのように役立ちますか?誰かが非難されるべきなら、それは攻撃者であるべきです。非難に関係なく、サーバーのバグがあってもXSSに対して脆弱ではないクライアントは、脆弱であるクライアントよりも優れており、それ以外はすべて同等です。
マイクサミュエル

0

それが本当に必要な場合、評価は悪ではありません。しかし、私が偶然見つけたevalの使用の99.9%は必要ありません(setTimeoutのものは含みません)。

私にとって、悪はパフォーマンスでもセキュリティの問題でもありません(間接的には両方です)。evalのこのような不必要な使用はすべて、保守の地獄に追加されます。リファクタリングツールは破棄されます。コードの検索は難しいです。これらの評価の予期しない影響は軍団です。


5
setTimeoutにはevalは必要ありません。そこでも関数参照を使用できます。
Matthew Crumley、

0

JavaScriptのeval()が悪ではないのはいつですか?

私はいつもevalを使わないようにしています。ほとんどの場合、よりクリーンで保守可能なソリューションを利用できます。JSON解析でも Eval は必要ありません。Eval はメンテナンスの地獄に追加されます。理由もなく、ダグラス・クロックフォードのよ​​うな巨匠たちに嫌われています。

しかし、私はそれ使用されるべき一例を見つけました:

式を渡す必要がある場合。

たとえば、一般的なgoogle.maps.ImageMapTypeオブジェクトを作成する関数がありますが、zoomcoordパラメータからタイルURLを作成する方法をレシピに伝える必要があります。

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

3
これは、eval()が不要になるようにリファクタリングできるように見えます-tileURLexprは単なるテンプレートなので、replace()をうまく使用するとうまくいきます。それでも、質問を提出したときに頭に浮かんだ例を思い出させます。これは、スプレッドシート機能と同様に、評価する数式をユーザーが指定できるようにすることに関するものでした。もちろん、私は答えに影響を与えたくなかったので、そのときは言及しませんでした!
Richard Turner

8
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Casey Chu

0

使用例evalインポート

通常どのように行われるか。

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

しかしeval、少しのヘルパー関数の助けを借りて、よりよく見えるようになります:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable (このバージョンは具象メンバーのインポートをサポートしていません)。

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

2
アイデアの+1ですが、ここにバグがあります.replace(/name/g, name).replace('path', path)name文字列が含まれている場合"path"、あなたは驚きを得ることができます。
wberry 14年

1
の各プロパティに対して1つの変数を宣言するcomponentsと、コードの匂いが発生する可能性があります。コードをリファクタリングすると、「問題」が完全に解消される場合があります。現在の解決策は、単なる構文上の砂糖です。あなたがそうすることを主張するなら、私はあなたが配備の前に実行されるように、あなた自身のプリプロセッサを書くことを勧めます。それはeval本番コードから遠ざける必要があります。
Ruud Helderman

0

Evalは悪ではなく、単に誤用されています。

あなたがそれに入るコードを作成したか、それを信頼できるなら、それは大丈夫です。人々はevalでユーザー入力がどのように重要でないかについて話し続けます。じゃあ〜

サーバーに送られるユーザー入力がある場合、クライアントに返され、そのコードはサニタイズされずにevalで使用されます。おめでとうございます。ユーザーデータを誰にでも送信できるようにpandoraのボックスを開きました。

evalがどこにあるかに応じて、多くのWebサイトがSPAを使用します。evalを使用すると、ユーザーがアプリケーションの内部に簡単にアクセスできるようになります。今度は、そのevalにテープで記録してデータを再び盗む偽のブラウザ拡張を作成できます。

評価を使用するあなたのポイントが何であるかを理解するだけです。そのようなことをするためのメソッドを作成したり、オブジェクトを使用したりするだけの場合、コードの生成は実際には理想的ではありません。

今度はevalを使用する良い例です。サーバーは、作成したswaggerファイルを読み取っています。URLパラメータの多くは、という形式で作成されます{myParam}。したがって、エンドポイントが多いため、複雑な置換を行わなくても、URLを読み取ってテンプレート文字列に変換したいとします。だからあなたはこのようなことをするかもしれません。これは非常に単純な例です。

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

-1

コード生成。私は最近、仮想domハンドルバー間のギャップを埋めるハイパーバーと呼ばれるライブラリを書きました。これは、ハンドルバーテンプレートを解析し、それをハイパースクリプトに変換することによって行われます。ハイパースクリプトは最初に文字列として生成され、それを返す前に、実行可能コードに変換します。私はこの特定の状況で悪の正反対を見つけました。eval()eval()

基本的に

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

これに

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

このeval()ような状況でも、生成された文字列を1回解釈し、実行可能ファイルの出力を何度も再利用するだけでよいため、パフォーマンスは問題になりません。

ここで興味があれば、コード生成がどのように行われたかを確認できます。


「ハイパースクリプトは最初に文字列として生成されます(...)」ビルドフェーズですべてのコード生成を行い、結果のハイパースクリプトコードを別の実行可能(.js)ファイルに書き込み、そのファイルをテストおよび製造。コード生成の使い方が大好きです。それevalは、コンパイル時の責任の一部がランタイムに移行したことのヒントです。
Ruud Helderman

-1

私の考えでは、evalはクライアント側のWebアプリケーションにとって非常に強力な機能であり、安全です... JavaScriptほど安全ではありませんが、そうではありません。:-)現在、Firebugなどのツールを使用すると、任意のJavaScriptアプリケーションを攻撃できるため、セキュリティの問題は本質的にサーバー側の問題です。


1
の使用はeval、XSS攻撃から保護する必要があります。
ベンジャミン

-1

Evalは、マクロがない場合のコード生成に役立ちます。

(愚かな)例として、Brainfuckコンパイラーを作成している場合は、一連の命令を文字列として実行する関数を作成し、それを評価して関数を返す必要があります。


コンパイラー(生成されるコードを実行するのではなく保存する)を作成するか、インタープリターを作成します(各命令にはコンパイル済みの実装があります)。の使用例もありませんeval
Ruud Helderman

JavaScriptコードを生成し、それをすぐに実行したい場合(直接解釈よりもパフォーマンス上の利点があるとしましょう)、それはevalの使用例です。
Erik Haliewicz

いい視点ね; この記事では、Blocklyの例を見ました。evalオルタナティブ(Function)の方が高速で(MDNで説明されているように)、信頼性が高い(同じWebページで生成されたコードと他の「サポート」コードとの間の分離が改善され、予期しないバグが防止される)場合、Googleが推奨することに驚いています。
Ruud Helderman

-5

解析関数(jQuery.parseJSONなど)を使用してJSON構造を解析する場合、JSONファイルの完全な構造が期待されます(各プロパティ名は二重引用符で囲まれています)。ただし、JavaScriptの方が柔軟性があります。したがって、eval()を使用してそれを回避できます。


4
eval特に盲目的に使用しないでください。サードパーティのソースからJSONデータを取得するとき。プロパティの引用符なしのJSON.Stringifyを参照してください「引用符で囲まれたキー名のないJSON」を解析するための正しいアプローチ。
Rob W

2
プロパティ名を二重引用符で囲まない場合、それはオブジェクトリテラルの文字列表現である可能性がありますが、JSONではありません。JSONは、プロパティ名をとしてstring定義し、バックスラッシュエスケープを使用して、二重引用符で囲まれた0個以上のUnicode文字のシーケンスstringとしてを定義します。
役に立たないコード

Nikolas Zakasによる記事を参照してください-"eval()は悪ではなく、誤解されている" nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood
vitmalina

@vitmalinaからZakasの記事:「ユーザー入力を取得してeval()を介して実行している場合、これは危険です。ただし、ユーザーからの入力でない場合、実際に危険はありますか?」それがまさに問題です。コードが「hello world」の比率を超えると、ユーザー入力をにリークしていないことを証明することはすぐに不可能になりますeval。深刻なマルチテナントWebアプリケーションでは、何十人もの開発者が同じコードベースで作業しているため、これは受け入れられません。
Ruud Helderman、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.