web-dev-qa-db-ja.com

ES6テンプレートリテラルはevalより安全ですか?

テンプレートリテラルは私にはevalのような匂いがしますが、 evalを使用するのは悪い考えです とよく言われます。

テンプレートリテラルのパフォーマンス には関心がありませんが、インジェクション攻撃(および私が考えていない可能性のあるその他のセキュリティ上の懸念)には関心があります。

編集

私には奇妙に感じる何かの例

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);

どの出力

1、2、3

テンプレートリテラルは、グローバルレベルで副作用を引き起こしています。機能によるものと直接的なものの両方。

編集2

テンプレートリテラルの安全性を示す例

let ii = 1;
let inc = function() { ii++; }
console.log('Starting: ' + ii);
let input = Prompt('Input something evil (suggestion: inc() or ii++)');
console.log(`You input: ${input}`);
console.log('After template literal: ' + ii);
eval(input);
console.log('After eval: ' + ii);

プロンプトが表示されたらii++を入力すると、ログに記録されます

開始:1

入力:ii + = 1

テンプレートリテラルの後:1

評価後:2

編集3

ECMAScript仕様の調査を開始しました

詳細については説明していませんが、テンプレートリテラルはevalよりも安全に指定されているように感じます。

18
Anthony Astige

evalとの違いの1つは、テンプレートリテラルがコンパイル時に解析されるのに対し、evalの引数は、実行時にevalが実行されるときにのみ解析されることです。

これに関連して、evalは動的に構築された引数を取得できますが、テンプレートリテラルは... literal:テンプレートとして保存できませんvariable =、動的に構築し、移動し、最終的に解析することができます。「テンプレート変数」データ型はありません。タグ関数は、実際には引数としてテンプレート変数を取得しませんが、コンパイル時に認識される、その解析されたコンポーネントを取得します。

いくつかの例

evalを使用すると、次のような状況になる可能性があります。

var code = Prompt('enter some evil code');
eval(code);

しかし、それはテンプレートリテラルでは不可能です。

var literal = Prompt('enter some evil template literal');
tag literal; // there is no data type or syntax for this.
`${literal}`; // and this just gives you the entered string.

可能なことは、これです:

var str = Prompt('enter some string');
tag`${str}`;

しかし、それが不要なコードの実行につながることはありません。少なくともこれより悪くはありません。

var str = Prompt('enter some string');
myfunc(str);

関数呼び出しはすべて、テンプレートリテラルにリテラルですでにエンコードされている必要があります。文字列変数の値はそれを変更できません。変数関数がテンプレートリテラルによって呼び出される方法はありません。この:

`${func(str)}`;

... funcを呼び出し、その関数のみを呼び出します。それはプログラマーによって選ばれます。

かなり邪悪なテンプレートリテラル

そうは言っても、これはまだ可能です:

var func = Prompt ("enter some evil function name (suggestion: 'alert')");
var param = Prompt ("now provide an argument for " + func);

`${window[func](param)}`;

しかし、プログラム喜んでがグローバルオブジェクトで任意の関数を実行する可能性を開くことは明らかです。そして確かに、あなたはevalの悪に近づいています。

同じ効果が次の場合にも達成されることに注意してください。

window[name](param);

最も邪悪なテンプレートリテラル

コメントしたように、このテンプレートをリテラルにすることもできます。

`eval(str)`;

...したがって、テンプレートリテラルには悪の部分はそれほど多くありませんが、その中にある設計の汎用関数呼び出しがあります。そのためには、テンプレートリテラルやevalは必要ありませんが、悪いプログラマーです;-)

例について

あなたはこの例を挙げました:

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);

これによりcounter関数が実行されますが、evalとの違いは、文字列リテラルが設計時にすでに存在しており、実行時に構築できなかったことです。このコードは設計カウンターをインクリメントするためのものであり、基本的に次のものと同じです。

console.log(counter() + ', ' + (ii++) + ', ' + counter());

コンパイル時間

コンパイル/実行時の解析の違いを強調するために、有効な構文を持たないテンプレートリテラルを使用してコードを実行することはできないことに注意してください。

次の2つのスクリプトを比較してください。

alert('press OK');
eval('alert("hello)');

そして:

alert('press OK');
`${alert("hello)}`;

構文エラーに注意してください。最初のスクリプトは、実行時にevalへの引数が解析されたときにのみ構文エラーに気付きますが、2番目のスクリプトは実行されないため、すぐに構文エラーが発生します。

より正確に言えば、evalは、独自のコンパイルフェーズと実行フェーズで新しいスクリプトを実行します。テンプレートリテラルは、他のコードと同様に解析/コンパイルされます。

27
trincot

evalテンプレートリテラルには大きな違いがあると思います。

evalは、コードから直接表示されない動的式を評価できます。これは危険です。クライアント/サードパーティ/データベースなど、どこからでも発生する可能性のある文字列を評価できるからです。

ただし、テンプレートリテラルの場合は状況が異なります。

  • コードから完全なテンプレートを見ることができるので、
  • 式は内部オブジェクトで機能し、動的式を評価することはできません。

たとえば、これはevalで機能します

function doSomething() {
  console.log('HELLO!');
}
    
// This will work.
var expression = 'doSomething()';
eval(expression);
  

ただし、これはテンプレートリテラルでは機能しません

// This will not.
`${expression}`;

それを機能させるには、式を静的に挿入する必要があります

// To make it work you need to insert it statically.
`${doSomething()}`;

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

2
gevorg

テンプレートリテラルは、それが懸念事項である場合、自動的に引用符をエスケープします。また、何も評価または実行せず、入力したものを文字列に変換します。 SQLインジェクションが心配な場合は、テンプレートリテラルを使用して試してみてください。そうすると、SQLインジェクションがエスケープされることがわかります。

本当に正当な理由を使用する必要があり、目標を達成するためにevalが必要であることが本当にわかっている場合を除いて、evalの使用は避けてください。それ以外の場合は回避するのが最善です。

0
Azamantes