質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

script要素におけるXSSについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 176

aae_11

score 68

体系的に学ぶwebアプリケーション第2版の「4.3.2」章「クロスサイトスクリプティング(発展編)」を読み、勉強していたのですが、分からない部分があった為、質問させて貰いました。
分からなかった箇所は、script要素内のjavascriptの一部を動的生成する場合のXSS脆弱性についての部分です。
script要素内はタグや文字参照を解釈しないので、HTMLとしてのエスケープは必要なく、JavaScriptの文字列リテラルとしてのエスケープを行うが、それだけでは不十分だとの説明がありました。
以下は本に記載されていた、PHPから指定した文字列とその文字数を表示するスクリプトです。

<?php
session_start();
function escape_js($s) {
  return mb_ereg_replace('([\\\\\'"])','\\\1',$s);
}
?>
<body>
  <div id="name"></div>
  <script>
    var div = document.getElementById('name');
    var txt = '<?php echo escape_js($_GET['name']); ?>';
    div.textContent = txt + 'の文字数は' + txt.length + '文字です';
  </script>
</body>


このスクリプトはうまくいくように見えるが入力中に「</script>」が含まれている場合、そこでJavascriptのソースの終端となるとの説明が記載されていました。しかし、次のページに、「HTML5の規格では、script要素内のデータには
「</script」という文字の並びは出現できないことになっている」とも書かれていました。
ここで、混乱してしまったのですが、「HTML5の規格では、script要素内のデータには「</script」という文字の並びは出現できないことになっている」としたら、「入力中に「</script>」が含まれている場合」も問題がないのではないかと思ってしまいました。また、「script要素内はタグを解釈しない」のであれば、そもそも「</script>」が解釈されないのではないのでしょうか...?
こちらの部分について、少し混乱してしまい分からなくなってしまった為、ご説明頂けましたら幸いです。
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+5

以下の箇所ですが…

ここで、混乱してしまったのですが、「HTML5の規格では、script要素内のデータには「</script」という文字の並びは出現できないことになっている」としたら、「入力中に「</script>」が含まれている場合」も問題がないのではないかと思ってしまいました。

元々のscript要素が以下のようになっているとします。ZZZが外部入力です。

<script>XXXXXXXXXX ZZZZZZZ XXXXXXXXXXX</script>

この ZZZZZZZ に </script><script>alert(1)// を設定すると、上記は以下のようになります。

<script>XXXXXXXXXX </script><script>alert(1)// XXXXXXXXXXX</script>

前半の XXX... は途中でちぎれていて構文エラーになりますが、その場合でも2番目のscriptは実行されます…というのが攻撃の流れです。

ここで、「script要素内のデータには「</script」という文字の並びは出現できないことになっている」ですが、これはあくまで文法上の約束なので、

  • script要素内のデータには「</script」という文字の並びは出現しないことが保証されている

ではなく

  • script要素内のデータには「</script」という文字の並びは出現しないようにプログラマが責任を持たなければならない

ということです。サンプルの脆弱なスクリプトはこの処理が入っていないことが脆弱性の原因です。


すみません。確認の為、追加でお聞きしたい箇所があるのですが、<script>要素内ではタグは解釈されないが、特別に</script>は認識されてしまうため、</script>が出現しないようにプログラマが気をつけなければならないといった理解で合っていますでしょうか...?
また、</script>がタグとして解釈されてしまうのは、javascriptの仕様なのでしょうか?

違います。
「タグが解釈されない」というのは、&lt; などが文字実体参照とてではなく、文字通りに扱われるという意味です。あるいは、<BR>という改行タグがあっても、改行という意味ではなく「<BR>」という文字列として扱われるという意味です。
そもそもの問題として、<script>要素は、</script>までで終わるわけです。これは正常な場合でもそうですよね。なので、ブラウザは、<script>要素が始まったら、</script>という文字列を探し、これらのタグに囲まれた範囲をJavaScriptの処理系に渡すわけです。タグの解釈をしないというのは、前述のように<BR>を改行と解釈しない等のことであって、</script>でscriptタグの終わりであることは識別しないことには、どこまでがscript要素かわからなくなります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/29 09:33 編集

    ご丁寧にご回答頂きましてありがとうございます。
    分からなかった点が、解明でき、助かりました。
    すみません。確認の為、追加でお聞きしたい箇所があるのですが、<script>要素内ではタグは解釈されないが、特別に</script>は認識されてしまうため、</script>が出現しないようにプログラマが気をつけなければならないといった理解で合っていますでしょうか...?
    また、</script>がタグとして解釈されてしまうのは、javascriptの仕様なのでしょうか?
    お手数ですが、ご返信頂けましたら幸いです...

    キャンセル

  • 2019/09/29 09:42

    本文の方に追記しましたので御覧ください

    キャンセル

  • 2019/09/29 10:00

    追記頂きありがとうございます。
    ご丁寧にご説明くださり、理解することができました。

    キャンセル

0

(1)
var a = '</div>';
alert('aは「' + a + '」です');

(2)
var a = '</html>';
alert('aは「' + a + '」です');

上記(1)の場合も(2)の場合も</div>や</html>がタグとして認識されることはありません。
ただの文字列です。
(</html>って書いてあるからってここでhtmlが終わりになるわけではありません)

ただし!

var a = '</script>';
alert('aは「' + a + '」です');

この場合はタグとして認識され、「</script>」が登場した時点でscriptは閉じられてしまいます。
chromeの検証などで確認してみてください。var a = '</script>'; の
</script>の部分の色が変わりタグとして認識されていることがわかります。

その結果、想定しない挙動になる可能性がありますので下記のようにエスケープする必要があります。
var a = '<\/script>';

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/29 10:06 編集

    ご回答頂きまして、ありがとうございます。
    混乱してしまっていたのですが、「</script>」が登場した時点で他の「<div>」などとは違いスクリプトが終了してしまうといった訳だったのですね。
    ockeghemさんのご回答とともに参考にさせて頂いたのですが、分からなかった箇所が解明でき、助かりました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる