これがアイデアです。静的アナライザー (たとえば、 esprima で作成できるもの) を使用して、eval されたコードが使用する外部変数を特定し、それらにエイリアスを設定した場合はどうなるでしょうか。「外部コード」とは、評価されたコードが使用するが宣言しない変数を意味します。次に例を示します。
eval(safeEval(
"var x = window.theX;"
+"y = Math.random();"
+"eval('window.z = 500;');"))
ここで、safeEval は、外部変数へのアクセスをブロックするコンテキストで変更された JavaScript 文字列を返します。
";(function(y, Math, window) {"
+"var x = window.theX;"
+"y = Math.random();"
+"eval(safeEval('window.z = 500;');"
"})();"
これでできることがいくつかあります。
- eval されたコードが外部変数の値を読み取ったり、それらに書き込んだりできないようにすることができます (
undefined
関数の引数として渡すか、引数を渡さないことにより)。または、変数が安全にアクセスされていない場合に、単に例外をスローすることもできます。
- また、eval によって作成された変数が周囲のスコープに影響を与えないようにします。
- 関数パラメーターとしてではなく、クロージャーの外側でこれらの変数を宣言することにより、eval が周囲のスコープで変数を作成できるようにすることができます。
- 外部変数の値をコピーし、それらを関数への引数として使用することで、読み取り専用アクセスを許可できます
- safeEval にそれらの特定の名前をエイリアスしないように指示することで、特定の変数への読み取り/書き込みアクセスを許可できます。
- eval が特定の変数を変更しないケースを検出し、エイリアスから自動的に除外できるようにすることができます (例: この場合、Math は変更されていません)。
- 周囲のコンテキストとは異なる可能性のある引数値を渡すことにより、実行するコンテキストを eval に与えることができます
- 関数から関数の引数も返すことでコンテキストの変更をキャプチャできるため、eval の外部でそれらを調べることができます。
の使用は特殊なケースであることに注意してください。これはeval
、その性質上、別の関数で効果的にラップすることができないためです (これが、 を実行する必要がある理由ですeval(safeEval(...))
)。
もちろん、この作業をすべて実行するとコードが遅くなる可能性がありますが、ヒットが問題にならない場所も確かにあります。これが誰かに役立つことを願っています。また、誰かが概念実証を作成した場合は、ここにリンクを表示したいと思います。)