kenju's blog

About Programming, Mathematics, Security and Blockchain

JavaScriptでeval()をWeb Workerで実行する

Serverless Single Page Apps: Fast, Scalable, and Availableを読んでいた時に、↓のテクニックについて知った。

tl;dr

  • ユーザーからの入力値をeval()に渡すのは、悪意のあるスクリプトを実行される可能性があるので基本的にご法度
  • しかし、JavaScriptのmainスレッドと別のコンテキストであるWeb Workerで実行することで、リスクは分離できる
  • JavaScriptのクイズアプリなどで要件的にどうしてもeval()を使わなくてはいけない場合、この手法が使える

課題

eval()をmainスレッドと分離したコンテキストで実行しないと、アプリケーション側のコードの改ざんやデータの抜き取り、XSSなどに繋がってしまう。

解決策

Web Workerを用いる。

public/app.js:

  function checkAnswer() {
    var worker = new Worker('worker.js');
    worker.onmessage = function(event) {
      if (event.data) {
        // handle event.data
      } else {
        // handle error (e.g., throw Error, Promise.reject(), ...)
      }
    }
    var userInput = `${user.inputted.text}();`; // can be malicious
    worker.postMessage(userInput);
  }

public/worker.js:

onmessage = function(event) {
  try {
    // here we call `eval()`
    postMessage(eval(event.data));
  } catch(e) {
    postMessage(false);
  }
}