48436


PHPの参考書でXSS対策として、「動的に生成される全ての値に対して」エスケープ処理をすべき、との説明があります。  
インターネット上では、print / echo の関数と共に簡易に紹介され記事ばかりのような気がします。

実際にサイトの開発作業を進めていく上で、どう活用すべきか理解したいので教えてください。

①html出力時だけで良い  
②逆に、画面から入ってくる内容についても（DB書き込む以前に）対応すべき  
③上記①の出力項目にしても、当該サイトから登録されたDB上の内容でなければ不要である  
（画面制御用のラジオボタンのリストなどは予めDBに登録されているもの、と思う）

一体どれが当てはまるでしょうか？  
「動的に生成される全ての値に対して」をもう少し具体的に知りたいです．．．


CC BY-SA 4.0
2018-09-15T11:43:20.430
48426
2018-09-15T15:55:38.920
25696
question
php
PHP htmlspecialchars関数の利用場面を教えて下さい。


「動的に」と言うのは、PHPの変数に入っている値は全部、それらからPHPの関数などで作られる値も全部入っている、と考えるといいでしょう。(以下簡単に「変数等」と書きます。)

ただし大前提として、『その「変数等」はHTMLを表していない』場合に限ります。あとで具体例を示します。

「生成される」の部分は「HTMLとして生成される」のことですね。これは字句通り「HTML出力時」ではなく、「HTML生成時」と解釈してください。

**_①html出力時だけで良い_**

上に書いたように「HTML出力時」でなく、全ての「HTML生成時」に行ってください。

ちょっとした擬似コードで説明します。まずはまったくXSS対策がなっていない方から。

[code]

    <?php
        //...
        $username = ...(DBか入力パラメータかは知らないがユーザの表示名が入る);
        $heading_html = '<h1>'.$name.'さんのページ</h1>';
    ?>
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
      </head>
      <body>
        <?=$heading_html?>
        <div class="greetings">
          ようこそ、<?=$name?>さん
        </div>
      </body>
    </html>
    
[/code]

上で(大文字の)「HTML出力時」と言っているのは、`<?=$heading_html?>`や`<?=$name?>`のところですが、このうち`<?=$heading_html?>`にはHTMLのタグなんかが含まれていますから、これを再度`htmlspecialchars`でエスケープしてしまうと、ユーザにタグをそのまんま見せてしまいます。こちらは「HTML生成時」には当たらないと思ってください。

代わりにこちら

[code]

    $heading_html = '<h1>'.$name.'さんのページ</h1>';
    
[/code]

`$heading_html`は、タグを含む文字列、つまりHTMLなので、この行は「HTML生成時」に含めないといけません。

と言うわけで、上記のコードに正しく`htmlspecialchars`を適用すると、こうなります。

[code]

    <?php
        $name = ...;
        $heading_html = '<h1>'.htmlspecialchars($name).'さんのページ</h1>';
    ?>
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
      </head>
      <body>
        <?=$heading_html?>
        <div class="greetings">
          ようこそ、<?=htmlspecialchars($name)?>さん
        </div>
      </body>
    </html>
    
[/code]

基本的には、HTMLとして出力される変数等は必ず、`htmlspecialchars(` `)`で囲む。  
HTMLを表す文字列を作成する場合も、変数等は必ず、`htmlspecialchars(` `)`で囲む。  
HTMLを表す文字列を出力する場合のみ、例外的に`htmlspecialchars`は付けない。  
(その場合は変数名の命名ルールなんかを工夫して「エスケープ不要」であることをわかりやすくした方が良いですね。)

最近はPHPでもテンプレートエンジンなるものを使う例も増えてきているので、その場合、それぞれのエンジンごとに注意点や正しくエスケープする作法なんかが異なります。

**_②逆に、画面から入ってくる内容についても（DB書き込む以前に）対応すべき_**

これは逆にやってはいけない、にあたります。DBにデータを入れるときにエスケープしてしまうと、HTML生成時に二重エスケープされることになり、ユーザに変な記号を見せることになってしまいます。

※DBに入れるデータにはHTMLのタグ入れちゃいけない、と決めてしまった方が良いでしょう。CMSなんかを自前で作ろうと思うとそうも言ってられないんですが、その場合でも「HTMLが入れられるカラム」と「プレーンテキストのカラム」は明確に分離した方が良いと思います。上の話は「プレーンテキストのカラム」前提です。

※一部のブラウザでは、`textarea`等から送信されてくる文字列に文字実体参照(あるいは数値文字参照、`&...:`とか`&#...;`てやつ)が含まれる場合があります。これではプレーンテキストとして扱えないので、DBの「プレーンテキストのカラム」に格納する際に、ちょっとした前処理が必要になります。(DB,PHPが共にUTF-8に設定していないと、ちょっと大変かも。)

**_③上記①の出力項目にしても、当該サイトから登録されたDB上の内容でなければ不要である  
（画面制御用のラジオボタンのリストなどは予めDBに登録されているもの、と思う）_**

上に書いたようにDBにどのような形式で保存されているかによります。DBにHTMLを登録できるようにしてあるのであれば、それをHTML出力するときにエスケープすると二重エスケープになってしまいます。できるだけそんなDB設計にしない方が良いとは思いますが、避けられない場合にはDBの「HTMLが入れられるカラム」に入れる値を作る時が「HTML生成時」に当たると思ってください。

* * *

長くなった割には質問者さんが疑問に思われているケースがうまく説明できていないかもしれません。何かありましたら、コメント等でお知らせください。


CC BY-SA 4.0
2018-09-15T15:55:38.920
48436
2018-09-15T15:55:38.920
13972
48426
answer