Firebugのconsoleを有効にしているとWebページ側からクリップボードを上書きされる危険性がある
簡単に言うと、下のようなコードをWebページ側が仕込んでいると、ユーザーが気づかないうちにクリップボードを書き替えられてしまう。
<script> window.addEventListener("load",function(){ alert("クリップボード置き替えのテスト"); window._FirebugCommandLine.copy("クリップボードが置き替えられてしまう"); },false); </script>
これは、FirebugがWebページ側に特権を昇格されてしまわないように、拡張機能と、コンソールのやり取りをイベントで間接的に行なうようにしたことに起因する問題。
以下、いろいろ調べて分かったことのメモ。
例えば、
console.log("foo");
というコードが実行されてから、実際にconsoleに表示されるまでを辿ってみる。
まず、
console.log.toString(); /* "function anonymous() { return window.console.notifyFirebug(arguments, "log", "firebugAppendConsole"); }" */
を実行して分かるように、実際の処理は、window.console.notifyFirebugで行っている。
window.console.notifyFirebug.toString(); /* function (objs, methodName, eventId) { var element = this.getFirebugElement(); var event = document.createEvent("Events"); event.initEvent(eventId, true, false); this.userObjects = []; for (var i = 0; i < objs.length; i++) { this.userObjects.push(objs[i]); } var length = this.userObjects.length; element.setAttribute("methodName", methodName); element.dispatchEvent(event); var result; if (element.getAttribute("retValueType") == "array") { result = []; } if (!result && this.userObjects.length == length + 1) { return this.userObjects[length]; } for (var i = length; i < this.userObjects.length && result; i++) { result.push(this.userObjects[i]); } return result; } */
まず、this.getFirebugElement()で、_firebugConsoleというidの要素を取ってくる(consolethis.getFirebugElement().toString()を実行してみると分かるが、実際には、見つからなかった場合に新たに作ってdocument.documentElementの最後に挿入する)。
そして、this.userObjectsに、console.logの引数の配列を入れて、elementのmethodNameにlogという文字列を入れて、firebugAppendConsoleというイベントを、elementでdispatchする。
分かったことは、
- Firebugとのやり取りは、window上に定義されたグローバルなオブジェクトのメソッドで実行されている
- console上で実行されたものか、Webページ側で実行されたものなのかを判別することができない
ということ。
console上でJSを実行すると、dirxmlやcopy関数があたかもグローバルにあるかのように使える仕掛けについて。
consoleで、下記のコードを実行すれば分かるように、withを使っている。
new Error().stack; // /* Error()@:0 ("with (_FirebugCommandLine) {\n copy(new Error().stack); \n};")@http://d.hatena.ne.jp/javascripter/:85 ("with (_FirebugCommandLine) {\n copy(new Error().stack); \n};")@http://d.hatena.ne.jp/javascripter/:84 ([object Event])@http://d.hatena.ne.jp/javascripter/:65 */
つまり、copyは実際には、window._FirebugCommandLine.copyを呼んでいる。なので、Webページ側からも普通に呼べてしまう。以上。