2761


javascript(coffeescript)を使い、ajaxで取得したhtmlコードをinnerHTMLでDOM要素に突っ込んでいます。
このとき、htmlコードの中にscriptタグを入れていてもjavascriptが実行されないのですが、

  1. 実行されないのは標準の挙動でしょうか？それともブラウザが気を利かせていての挙動でしょうか？
  2. セキュリティを考慮した上で意図したスクリプトだけ実行させるにはどうすればいいでしょうか？

以前にハマったんだけどうやむやにしてたら今日またハマって、たぶん時間かけて調べてもまた結局わからずじまいになりそうなうえにこれ理解してないのまずい気がするので、どうか怒らないで教えてください。


CC BY-SA 3.0
2014-12-28T16:49:13.227
2756
2014-12-28T23:03:16.693
705
question
javascript
innerHTMLに入れたコードの中にscriptタグがあっても実行されないのはなぜ？


  1. `innerHTML`に`script`タグを入れても動かない原因は、ブラウザが一度その中身を`DOM`として解釈を試みるからです。`script`タグはうまく解釈されないため、おそらく取り除かれるのでしょう。

  2. については色々な方法があるでしょうが、例えば以下のようにすると動きます。(もしかするとFirefox以外のブラウザでは動かないかもしれません。)
[code]     var name = "<img src=x onerror=alert(1)>";

    el.innerHTML = name; 
    
[/code]

cf. [Element.innerHTML - Web API Interfaces |
MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML)

尚、英語版にも似たような質問がありましたので、一応貼っておきます。

[javascript - Can scripts be inserted with innerHTML? - Stack
Overflow](https://stackoverflow.com/questions/1197575/can-scripts-be-inserted-
with-innerhtml)


CC BY-SA 3.0
2014-12-28T17:12:03.940
2757
2014-12-28T18:30:19.370
2017-05-23T12:38:56.467
-1
3313
2756
answer


2 に関して、以下の様なコードは実行可能でした。

[code]

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <script>
            function append(code){
                var script = document.createElement('script');
                script.innerText =code ;
                script.textContent = code;
                document.body.appendChild(script);
            }
        </script>
    </head>
    <body>
    <button onclick="append('alert(10);');">xxx</button>
    </body>
    </html>
    
[/code]

セキュリティを考えるのであれば、コードを受け付けるよりもjsonなど値だけ受け取る形がいいと思います。


CC BY-SA 3.0
2014-12-28T17:35:34.787
2758
2014-12-28T17:35:34.787
5857
2756
answer


  1. 実行されないのは標準の挙動 (仕様通り) です。

実行条件は [4.11.1 The script element](http://www.w3.org/TR/2014/REC-
html5-20141028/scripting-1.html#the-script-element) に記載されていますが、`script` 要素の
`src` や `async` などの属性の有無や、`script`
要素の生成方法など、様々な条件を網羅して記述されているため、きちんと読むのは正直結構しんどいです。

ただ、`innerHTML` を使ったケースでは「実行されない」という結果については、ちょうど Note に記述されています:

> Note: When inserted using the document.write() method, script elements
> execute (typically synchronously), but when inserted using innerHTML and
> outerHTML attributes, they do not execute at all.

なお、実行はされずとも `script` 要素はきちんと DOM ツリー上に作られています。

  2. 意図したスクリプトを実行するためには、`element.innerHTML` のようなHTML文字列をパースして自動的に DOM 要素を作るインタフェースは用いずに、[@kleaf さんの回答](https://ja.stackoverflow.com/a/2758/3158) のように `document.createElement` や `document.createTextNode` (または `node.textContent` )で `script` 要素を構築するのが間違いないかと思います。これならば実行されないという条件に入らないので。

逆に、意図せずスクリプトが実行されないようにするためには、やはり `innerHTML` ではなく `document.createTextNode`
を使って、入力値から DOM 要素を作らせない (テキストしか作らせない) ようにすればいいです。そうではなく、入力値から安全に DOM
要素を生成するという要件であれば、スクリプト文字出力時のエスケープ処理を行う必要があります。


CC BY-SA 3.0
2014-12-28T22:57:12.317
2761
2014-12-28T23:03:16.693
2017-04-13T12:52:39.113
-1
3158
2756
answer