2012-02-16
■ PHP で h() を書くなら一緒に echo しよう。

名前が長い関数 htmlspecialchars() を h() と書けるようにすると便利、という話がある。
- PHP: htmlspecialchars - Manual
- htmlspecialchars関数を簡単に扱えるようにする
- CakePHPで高速Webアプリ開発:第1回 CakePHPを使いたくなる5つの特徴|gihyo.jp … 技術評論社
htmlspecialchars() なんて長い名前は絶対忘れるし、ENT_QUOTESだのUTF-8だのも書き忘れるに決まっている。
h() は CakePHP でも使われていて、いいと思う。いいと思うんだけど、もうちょっといける。
<?php /** 改善前のエスケープ関数 */ function h($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8') }
このようにエスケープした結果をreturnで返すと、エスケープと出力を離して書けてしまう。
$name = h($name); : // 長い長い処理の後に : <?php echo $name; // たしかエスケープ済だったかな ?> <?php echo h($address); // こっちはエスケープしてなかったかも ?>
これだとぜったいエスケープし忘れる。もしくは二重にエスケープする。
エスケープが常に出力の直前になるように h() の中で echo も実行するといい。エスケープしていない(echoが直に書かれた)箇所を目立たせる結果にもなる。
<?php /** * HTMLの特殊文字をエスケープして結果を出力します。 */ function h($str) { echo htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); }
次のように使う。
<?php h($name); ?> <?php h($address); ?>
htmlspecialchars() を実行した文字列に対して更に何か加工するのは例外的なケースだが、よくあるのは改行を<br/>にする処理で、これは hbr() として定義する。
<?php /** * HTMLの特殊文字をエスケープして改行の前にbrタグを追加し、結果を出力します。 */ function hbr($str) { echo nl2br(htmlspecialchars($str, ENT_QUOTES, 'UTF-8')); }
それ以外は頑張って htmlspecialchars() と書く、と言いたいけど、ENT_QUOTES、'UTF-8'を忘れそうなので、やはり関数を定義しておいたほうが安心かも。h() を使いたくなるように、名前は長めにする。
<?php /** * HTMLの特殊文字をエスケープして結果を返します。通常は h() を使います。 */ function htmlescape($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); }
配列をまとめてエスケープといった話はすっぱり忘れる。やるなら htmlescapeArray(array $array) を定義して、処理内容を明確にする。
参考
「出力の直前に」「例外なく」「エスケープしていることがわかるように」
セキュリティ云々以前に、プログラムの開発方法論として、できるだけ局所的な視点でコードの正当性を確認できるように書くのが、近代プログラミングの基本だ。つまり、このコード断片だけ見て、問題がないとわかるように書くべきである。
:
たとえば、echo を全面的に使用禁止として次のように書くのもよいだろう。
高木浩光@自宅の日記 - プログラミング解説書籍の脆弱性をどうするか, 「サニタイズ言うなキャンペーン」とは何か, ASPとかJSPとかPHPとかERBとか、逆だ..
PHP で何かを出力する際には,それが人の目に触れる形で表示されるかどうかにかかわらず,出力の直前に htmlspecialchars() を必ず通すようにしましょう。
セキュリティ上の配慮
以下の文字列をサニタイズする。サニタイズするタイミングは、データ受付時ではなく、HTML出力直前に例外なく行うこと。
セキュリティ指針/クロスサイトスクリプティング - ゼンド・ジャパン株式会社 技術情報コンテンツ
はまちちゃん先生の記事に触発されて書きました。
- 170 http://b.hatena.ne.jp/monjudoh/mod_rewrite/
- 162 http://www.google.co.jp/url?sa=t&rct=j&q=javascript 正規表現&source=web&cd=5&ved=0CFoQFjAE&url=http://d.hatena.ne.jp/koseki2/20090530/JsIdiom&ei=Z8A9T72BGofwmAXVrfyxBw&usg=AFQjCNGqzyPuUsh6PbGLWLBqCGQHbHqw1g
- 110 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=18&ved=0CGAQFjAHOAo&url=http://d.hatena.ne.jp/koseki2/20090611/ModRewrite&ei=Re09T7KPFfDDmQWY26SyBw&usg=AFQjCNESmqRLEDH_mccczsOtUwJknDFLoA
- 94 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CDcQFjAB&url=http://d.hatena.ne.jp/koseki2/20090328/rubymail&ei=Imc_T661Ge7EmQWow6S-Bw&usg=AFQjCNEi8NoaPA7sO-BcwHx8782z0cUXng
- 92 http://www.google.co.jp/url?sa=t&rct=j&q=javascript+正規表現+名前付き&source=web&cd=1&ved=0CCcQFjAA&url=http://d.hatena.ne.jp/koseki2/20090530/JsIdiom&ei=MKU9T_7qAengmAX0pMG6Bw&usg=AFQjCN
- 60 http://www.google.co.jp/url?sa=t&rct=j&q=rsync exclude&source=web&cd=2&ved=0CDkQFjAB&url=http://d.hatena.ne.jp/koseki2/20090424/rsync&ei=Mqs9T9TUMKOUiQfr4qzLBA&usg=AFQjCNHeWqLDUqt4b9JYcgSJ4TrKepkuMA
- 50 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0CEIQFjAC&url=http://d.hatena.ne.jp/koseki2/20100422/CapistranoPlain&ei=u5g9T5auCoiViAfI2LW1BA&usg=AFQjCNH7a9Y0aOzQIiD6bn-qO4OxpoazeA&sig2=MJr35rECCjKPfsmkSfNBLQ
- 46 http://www.google.co.jp/url?sa=t&rct=j&q=javascript ヒアドキュメント&source=web&cd=1&ved=0CC8QFjAA&url=http://d.hatena.ne.jp/koseki2/20080112/jsheredoc&ei=fJE9T-S4Eq6XmQWV8sG6Bw&usg=AFQ
- 45 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CEIQFjAD&url=http://d.hatena.ne.jp/koseki2/20120210/phpuri&ei=egBCT7yXF8HamAWpwYnEBw&usg=AFQjCNGBZlFoJGvOQonJvlmLY9G6iwxrXw
- 38 http://www.google.co.jp/url?sa=t&rct=j&q=close_wait&source=web&cd=4&ved=0CFQQFjAD&url=http://d.hatena.ne.jp/koseki2/20070331/closewait&ei=mro9T9fJH4fEmQWS1fXdBw&usg=AFQjCNG5Z5GaM_ZCG1h-R8Eku8ivgMbyUg