CocytusというJSを書きました。

こんな感じで使います。

<script src="cocytus.js"></script>
<script>
var jail = Cocytus();
jail.run(function() {
  var l = 42;
  postMessage(l);
  g = 42; // see what happens in console
  postMessage(g);
});
</script>

といってもピンと来ないかと思われるので、デモを用意しました。



要するに、 Web Worker で sandbox を実現したわけです。あくまで sandbox なので、呼び出し側の document には手をかけません。

で、何が禁止されてるかというと、こんな感じです。

大域変数の宣言と初期化

Crockfordも大喜び?

var v = 1;
postMessage(v);
// it is okay to get existing global vars
postMessage(Object.getOwnPropertyNames(this));
// but you can't assign it...
undefined = 1;  // global object is frozen
postMessage(undefined);
// or set new global variable
g = 1;
postMessage(g);

eval()

あからさまな奴ばかりではなく…

postMessage(21+21);
postMessage(eval("21+21"));

やや控え目な奴や…

postMessage((function(){return 42})());
postMessage((new Function("return 42"))());

あまり控え目でない奴まで。副作用としてconstructor禁止になりはしますが。

postMessage((function(a){return a})(42));
postMessage(''.constructor.constructor('a', 'return a')(42));

Timeout

Cocytusは実行に制限を設けるのに加え、強制タイムアウトも実現しています。

function(){
    var n = 0
    setInterval(function(){ postMessage(n++) }, 100);
}

もちろんWorker側で自主的に切腹するのもありです。

function(){
    var n = 0
    setInterval(function(){ postMessage(n++) }, 100);
    setTimeout(function(){ close() }, 500);
}

きっかけと名前の由来

これです。

404 Blog Not Found:javascript - eval(insecure.code).safely with(jail); //でもIEが - nene2001さんのコメント
最近、必要が生じまして同様のJavaScript SandBox in pure JavaScriptに取り組んでおります。

コメント欄を見ての通り、元記事の方法はうまく行きません。

その一方、 Web Worker はかつて一部のブラウザーにのみ許された贅沢でした。それから幾星霜…ぼんやりとこの記事をiPad見ていたら、何事もなかったように動くではありませんか!

これと、ES5のObject.freeze()を組み合わせたら、もしかして…

いけました。ES5さまさまです。

とりあえず以下で動作する事を確認しています。

  • iOS 6 (Safari & UIWebView)
  • Safari 6 (Mac)
  • Android 4.x (Chrome and Built-in Browsers of Nexus 7 and Galaxy 3)
  • Chrome 25
  • Firefox 19
  • IE 10 (Windows 8)

名前の由来は、こちら。

コーキュートス - Wikipedia
コーキュートス(Cocytus, 希: κωκυτός)はギリシア神話において、地下世界(地獄)の最下層に流れる川で、「嘆きの川」を意味する。元来は「悲嘆」を意味している。

Object.freeze()が決定的な役割を果たしているのでこれにしました。

Enjoy!

Dan, not Dante, the JavaScripter

Source:

cocytus.js