javascript Eval機能の「不適切な使用」とは何ですか?[閉まっている]


13

Evalは、物議を醸すことで有名な言語機能です。ダグラス・クロックフォードは完全に拒否します。Evalがもたらす具体的なリスクについて疑問に思っています。よると、この質問、Improper use of eval opens up your code for injection attacks

Evalコマンドの不適切な使用法は何ですか?また、どのセキュリティホールが開きますか?

回答:


31

JScriptエンジンを実装していたとき、私はEVAL IS EVILシャツを印刷することを提唱しましたが、残念ながら私たちはそれに到達できませんでした。

evalに関する私の最大の問題は、明らかな悪意のあるコードインジェクション攻撃ではありませんが、それは確かに大きな懸念事項です。私の最大の問題は、人々が本当に小さな問題を解決するために本当に大きなハンマーとしてそれを使用する傾向があることです。私がJScriptチームにいたときの「評価」の実世界での使用のほとんどは、ルックアップテーブルを使用して簡単に解決できました。また、JScriptのすべてのオブジェクトは既にルックアップテーブルであるため、面倒な負担ではありませんでした。評価は再び、コンパイラを起動し、完全にあなたのコードを最適化するコンパイラの能力を破壊します

この脈絡についてのさらなる考えについては、2003年の主題に関する私の記事を参照してください。

一般的な悪:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

インジェクション攻撃の悪さ:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


evalJSPackerのようなアプリケーションが好む方法で、大量のコードを実行することについてのあなたの考えは何ですか?JSPacker + gzipは通常、それ自体のソリューションよりもファイルサイズが小さくなりますが、あなたが正しく指摘しているように、本質的に同じコードでコンパイラを2回起動し、さらに文字列置換を行うためのオーバーヘッドが発生します。
マシューシャーリー

2
@Matthew:空間と時間の間にはトレードオフがあることが多く、そのトレードオフを活用することが大きな勝利になることがあります。テクニックの目的がパフォーマンスを改善することである場合、慎重な測定がセキュリティホールを導入せずに現実的なシナリオで重要な勝利であることを示した場合、素晴らしいと思います。しかし、私はその詳細を批判する特定の手法について十分に知りません。
エリックリッパー

私は私が見ていた答えの1希望のいずれかここまたは SO自体には何をお使いの第2のリンクの状態を述べているだろう:それはeval()ありません、クライアント(ブラウザ)コード上のセキュリティリスク。
sq33G

4

ほとんどのセキュリティホールは、SQLインジェクションと同じ種類のホールです。つまり、ユーザー入力をJavaScriptコードに連結します。違いは、これをSQLで行わないようにする方法はありますが、JavaScriptでできることはあまりないことです。

単純で役に立たない例として、単純なJavaScript計算機:

textbox1.value = eval(textbox2.value);

正しい使用例の1つは、一般的な単語を引き出して1〜2文字の短い文字列に置き換えることでJavaScriptを圧縮するJavaScriptパッカーの一部です。パッカーは、生成された辞書に基づいて文字列置換コードとともにこれらすべてを出力し、結果を評価します。


1

EVAL-のような機能のないJSで行うことは不可能ないくつかのものがあります(evalFunction、そしておそらくより)。

apply例を挙げましょう。通常の関数呼び出しで使用する場合、簡単に使用できます。

foo.apply(null, [a, b, c])

しかし、新しい構文を介して作成しているオブジェクトに対してこれをどのように行いますか?

new Foo.apply(null, [a, b, c]) 機能せず、同様の形式も機能しません。

しかし、あなたは経由でこの制限を回避することができますevalFunction(私が使用してFunction、この例では):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

例:

Foo.New.apply(null, [a, b, c]);

もちろん、Function.prototype.New使用する関数を手動で作成することもできますが、この冗長で不格好なだけでなく、(定義により)有限である必要があります。Functionコードを任意の数の引数に対して機能させることができます。


2
確かに、OPの質問は、「Evalコマンドの不適切な使用と、それらのセキュリティホールはどのようなものですか?」ではなく、「何が適切な使用eval()ですか?
ロスパターソン

1
@RossPatterson:質問のタイトルをほとんど見ていたと思います。
トーマスエディング

それでも、悪い言語機能の良い使用法を見つけるための+1 :
ロスパターソン

1

私のやや直接的な答えは、開発者向けのAPIテスト領域を開発することでした。ページ上のテキスト領域と、実行ボタンを提供しました。ページの中心点は、ローカル環境では簡単ではなかったiframe通信APIに対してJavascriptで試すことができることでした。

その場合に行われる可能性のある悪意のあることはすべて、開発者がF12ツールを開いて行うこともできます。


0

非常にまれにしか使用しないことに同意しますが、の強力なユースケースを見つけましたeval

Firefoxには、私が取り組んできたasm.jsという実験的な新機能があります。Javascript言語の限られたサブセットをネイティブコードにコンパイルできます。はい、これは非常に素晴らしいですが、制限があります。Javascriptの限られたサブセットは、Javascriptに埋め込まれたCに似た言語であると考えることができます。それは実際に人間が読み書きすることを意図したものではありません。

Javascriptのこの限られたサブセットでは、コンパイルされたランタイムに生成されたコードを、コンパイルされたコードに挿入することはできません。

ユーザーが使い慣れた表記法で数式を記述し、その場でasm.jsコードに変換できるようにするコードを作成しました。コードをサーバー側で処理したい(そうしない)場合evalを除き、結果のコードをブラウザーでリアルタイムに処理できるようにする唯一のツールです。


0

他の人が指摘したように、作業する際の最も重要なことevalは、それを安全に保つことです。そのためには、徹底的な引数チェックをeval実行し、実行時生成コードの維持と保護が一般にはるかに難しいため、「ed」コードをシンプルにします。

そうは言っても、私evalは2種類のことを使うことを楽しんでいます(おそらく、より良い、より邪悪ではない選択肢があるかもしれませんが)。

  1. 以来eval、「明示的にキャッシュするコード」の方法です、パフォーマンスを向上させるために使用することができます。オプティマイザーは常に改善されていることに注意してください。ただし、オプティマイザーが何を実行できるかについての保証はありません。コード内で物事を明示的にすることで、オプティマイザーがより賢明な決定を下せるようにすることができます。
  2. また、パフォーマンスを低下させることなく、JSに欠けている他の言語機能と同様に、タイプセーフの基本的な形式を提供するために使用できます。

たとえば、このプリコンパイルされたオブジェクトイテレータアプローチはevalオブジェクトプロパティのイテレーションに使用する場合、パフォーマンスが明らかに向上することを示しています。また、暗黙の制約チェックなどを、ほとんどまたはまったくコストをかけずに提供できる強力な型システムの始まりを示しています。

Javascriptのベテラン開発者の多くは、これがうさぎの穴だと指摘するでしょう。なぜなら、この方法でJavascriptを書き始めると、基本的に言語の使用方法が変わるからです。ただし、Javascriptを楽しむ人にとって必ずしも悪いことではないかもしれませんが、言語自体の使用方法を変更することでしか達成できない基本的な言語機能もありません。


-3

文字列を評価し、文字列と同じ名前の既存の変数を返すevalのように見える状況があります。

いくつかのテーブルがあります:table1ResultsTable、table2ResultsTable、tableNResultsTable。同じ名前で設定された変数、つまりjQueryデータテーブルオブジェクトがあります。これらを使用してテーブルをセットアップし、jQueryデータテーブル関数を呼び出します。

各テーブルにはclass = "resultsTable"が割り当てられています。次に、テーブルをクリックしたときに変数を取得する必要があります。私はこれをやっています:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

そのため、セルがクリックされたテーブルのIDを取得しています。これは、それに対応するdatatableオブジェクト変数と同じ名前です。誰かが改善のための提案を持っている場合、私はそれについて知りたいです。


1
なぜevalが必要なのですか?idは、コードではなくプレーンな文字列である必要があります。とにかく、event.target.parentElement.parentElement.parentElement恐ろしいです。さらに、評価可能なIDを意図的に使用していない限り、eval呼び出しが「参照エラー:[id]が定義されていません」エラーを生成することを期待します(壊れている、間違っている、終了すると奇妙なことが起こる可能性があります)重複IDを生成します)。
ブライアン

おそらく、私は自分自身を明確にしていません。idはプレーンストリングです。クリックされたのはテーブルのIDです。また、idと同じ名前のオブジェクト変数(同じテーブルを参照するjQuery datatable()メソッドで設定)もあります。テーブルがクリックされたときに、変数を取得し、その関数にアクセスする(実際には、選択した行に「row_selected」クラスを追加する)ようにしています。しかし、これを書いて以来、私は改善を思いつきました。すべてのオブジェクト参照を配列に入れ、要素にidと同じ名前を付け、それにid文字列をプラグインしてオブジェクト参照を取得します。
ボブローズ

ブライアン、クリックされたテーブルのIDを見つけるより良い方法があれば、私はすべて耳にします。datatables関数では、セルに対するクリックイベントを処理し、row_selectedクラスをそのparentNodeに追加する必要があります。行イベントを処理してクラスを直接追加できないのはなぜかわかりませんが、行を選択したときに行が表示されません。
ボブローズ

1
おそらく、私は自分自身を明確にしていません。プレーン(つまり、非JS)文字列でevalを呼び出すと、例外がスローされます。したがって、evalを使用しても意味がありません。IDと同じ名前のオブジェクト変数を生成している場合、コードは機能しますが、壊れているように感じます。を使用して変数を作成しますdocument.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(どちらかが優れているとは言いませんが、evalよりも優れています)。Eric Lippertが指摘するように、「JScriptのすべてのオブジェクトはすでにルックアップテーブルです。」
ブライアン

さて、プロパティを要素参照に追加し、データテーブルオブジェクト参照に設定するように言っていますか?それは私にとってもきついですね。
ボブローズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.