質問: PHPの参考書でXSS対策として、「動的に生成される全ての値に対して」エスケープ処理をすべき、との説明があります。 インターネット上では、print / echo の関数と共に簡易に紹介され記事ばかりのような気がします。 実際にサイトの開発作業を進めていく上で、どう活用すべきか理解したいので教えてください。 1html出力時だけで良い 2逆に、画面から入ってくる内容についても(DB書き込む以前に)対応すべき 3上記1の出力項目にしても、当該サイトから登録されたDB上の内容でなければ不要である (画面制御用のラジオボタンのリストなどは予めDBに登録されているもの、と思う) 一体どれが当てはまるでしょうか? 「動的に生成される全ての値に対して」をもう少し具体的に知りたいです...
回答: 「動的に」と言うのは、PHPの変数に入っている値は全部、それらからPHPの関数などで作られる値も全部入っている、と考えるといいでしょう。(以下簡単に「変数等」と書きます。) ただし大前提として、『その「変数等」はHTMLを表していない』場合に限ります。あとで具体例を示します。 「生成される」の部分は「HTMLとして生成される」のことですね。これは字句通り「HTML出力時」ではなく、「HTML生成時」と解釈してください。 ***1html出力時だけで良い*** 上に書いたように「HTML出力時」でなく、全ての「HTML生成時」に行ってください。 ちょっとした擬似コードで説明します。まずはまったくXSS対策がなっていない方から。 ``` '.$name.'さんのページ'; ?> =$heading_html?> ようこそ、=$name?>さん ``` 上で(大文字の)「HTML出力時」と言っているのは、`=$heading_html?>`や`=$name?>`のところですが、このうち`=$heading_html?>`にはHTMLのタグなんかが含まれていますから、これを再度`htmlspecialchars`でエスケープしてしまうと、ユーザにタグをそのまんま見せてしまいます。こちらは「HTML生成時」には当たらないと思ってください。 代わりにこちら ``` $heading_html = ''.$name.'さんのページ'; ``` `$heading_html`は、タグを含む文字列、つまりHTMLなので、この行は「HTML生成時」に含めないといけません。 と言うわけで、上記のコードに正しく`htmlspecialchars`を適用すると、こうなります。 ``` '.htmlspecialchars($name).'さんのページ'; ?> =$heading_html?> ようこそ、=htmlspecialchars($name)?>さん ``` 基本的には、HTMLとして出力される変数等は必ず、`htmlspecialchars(` `)`で囲む。 HTMLを表す文字列を作成する場合も、変数等は必ず、`htmlspecialchars(` `)`で囲む。 HTMLを表す文字列を出力する場合のみ、例外的に`htmlspecialchars`は付けない。 (その場合は変数名の命名ルールなんかを工夫して「エスケープ不要」であることをわかりやすくした方が良いですね。) 最近はPHPでもテンプレートエンジンなるものを使う例も増えてきているので、その場合、それぞれのエンジンごとに注意点や正しくエスケープする作法なんかが異なります。 ***2逆に、画面から入ってくる内容についても(DB書き込む以前に)対応すべき*** これは逆にやってはいけない、にあたります。DBにデータを入れるときにエスケープしてしまうと、HTML生成時に二重エスケープされることになり、ユーザに変な記号を見せることになってしまいます。 ※DBに入れるデータにはHTMLのタグ入れちゃいけない、と決めてしまった方が良いでしょう。CMSなんかを自前で作ろうと思うとそうも言ってられないんですが、その場合でも「HTMLが入れられるカラム」と「プレーンテキストのカラム」は明確に分離した方が良いと思います。上の話は「プレーンテキストのカラム」前提です。 ※一部のブラウザでは、`textarea`等から送信されてくる文字列に文字実体参照(あるいは数値文字参照、`&...:`とか`...;`てやつ)が含まれる場合があります。これではプレーンテキストとして扱えないので、DBの「プレーンテキストのカラム」に格納する際に、ちょっとした前処理が必要になります。(DB,PHPが共にUTF-8に設定していないと、ちょっと大変かも。) ***3上記1の出力項目にしても、当該サイトから登録されたDB上の内容でなければ不要である (画面制御用のラジオボタンのリストなどは予めDBに登録されているもの、と思う)*** 上に書いたようにDBにどのような形式で保存されているかによります。DBにHTMLを登録できるようにしてあるのであれば、それをHTML出力するときにエスケープすると二重エスケープになってしまいます。できるだけそんなDB設計にしない方が良いとは思いますが、避けられない場合にはDBの「HTMLが入れられるカラム」に入れる値を作る時が「HTML生成時」に当たると思ってください。 長くなった割には質問者さんが疑問に思われているケースがうまく説明できていないかもしれません。何かありましたら、コメント等でお知らせください。