脆弱性対策におけるhtmlspecialchars()の使用箇所について


PHPでスクリプト挿入攻撃やXSS対策として、サイタイズのためにhtmlspecialchars()を使うことがあると思いますが、使用する際の詳細が気になったので質問します。具体的には以下の２点です：

  * サニタイズ関数を適用するタイミングについて  
【ユーザからの入力時】【HTMLへの出力時】【その中間】の３パターンが考えられますが、ベストなのはどれでしょうか？GET・POSTパラメータの処理と、その出力がほぼ同時に行われる場合では違いが顕在化しませんが、そうでないより一般的な場合に注意する点が知りたいです。

『パーフェクトPHP』330・334頁によると「出力時にエスケープ」とだけ書いてありますが、それに関連する詳細の記述やサンプルコードがないため背景知識があってそうなるのか、それとも単なる著者の思いつきなのか判断できません。

【ユーザからの入力時】にサニタイズしてしまうと、HTML出力以外でサニタイズ前の文字列が必要になった際にhtmlspecialchars_decode()等で元に戻す必要があるため、やはり【HTMLへの出力時】がベストなのでしょうか？

  * htmlspecialchars()とhtmlentities()の使い分けについて  
いずれも第２引数にENT_QUOTESを指定すると思いますが、サニタイズ目的に限る場合、htmlspecialchars()で十分でしょうか。それともhtmlentities()まで使用する必要があるでしょうか？

[get_html_translation_table()](http://php.net/manual/ja/function.get-html-
translation-table.php)で変換される文字の違いは分かるのですが、どこまでやればサニタイズ目的で十分なのかよく分かりません。

以上詳しい方いらっしゃいましたら、ご教示ください。




# ドメインレベルでの対策を行っていない場合

**「出力時にエスケープ」** 1択です。他の選択肢は考えられません。著者の思いつきではなく、ここ数年万人によって当たり前のように言われ続けていることです。

>
> 【ユーザからの入力時】にサニタイズしてしまうと、HTML出力以外でサニタイズ前の文字列が必要になった際にhtmlspecialchars_decode()等で元に戻す必要があるため、やはり【HTMLへの出力時】がベストなのでしょうか？

その通りですね。他にも **エスケープ忘れ** や **多重エスケープ**
といったミスを防ぐ意図もあります。「格納時にエスケープ」という手段を採用している某日本の大手Q&Aサイトは、今までに私が確認できただけでXSS脆弱性を3回に加えて多重エスケープも同じ回数ぐらい発生させてしまっています。後者に関しては今も放置されている箇所があります。

また、エスケープされた状態だと **_「n文字以内でトリミングする」という処理を書くのが困難_**
になります。上で挙げたQ&Aサイトや某短文投稿サイトでもこれに関して、エンティティ表記されている部分が途中でぶった切られる問題も発生していたりします。

# ドメインレベルでの対策を行い、ユーザの自由なＨＴＭＬ記述を許可している場合

はてなブログやFC2ブログなどでは、 **「ログインした状態で何かするページ」** にはHTML記述を一切認めず、 **「記事を表示するだけのページ」**
ではHTMLの使用を認めています。 そもそもエスケープしていないことになりますね。 **_記事を表示しているページ上で直接コメント等が出来ない_**
ことに気付くと思います。はてなブログはインラインフレーム埋め込み、FC2ブログは別ページへの移動となります。

# どちらを選ぶべきか

セキュリティに関して十分な知識があり、ドメインを用意できるならこちらの選択肢もアリです。但し基本的にはやはり前者の「出力時にエスケープ」の方が選択されるべきです。

# `ENT_QUOTES` の必要性

シングルクオートで括られた属性内に表示する際には必須です。但し一般的にはダブルクオートで括る方が主流なので、デフォルトの `ENT_COMPAT`
が必ずしも悪いというわけではありません。思考停止したように `ENT_QUOTES` を採用する必要はないです。

但し…

  * 文字セットのデフォルト値がPHPのバージョンによって異なるという大きな変更が過去にあった
  * 使用頻度が多い割に関数名自体が長い

という背景も踏まえて、どうせなら

[code]

    function h($str) {
        return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    }
    
[/code]

という関数を作ってしまっておいてそれを流用する方が良いでしょう。

# `htmlspecialchars` と `htmlentities`

セキュリティ対策が目的であれば前者で十分です。

# 参考リンク

  * [「サニタイズ言うなキャンペーン」とは何か](http://takagi-hiromitsu.jp/diary/20051227.html#p02)
  * [「サニタイズ言うなキャンペーン」私の解釈](http://kmaebashi.com/zakki/zakki0042.html)
  * [htmlspecialcharsは不正な文字エンコーディングをどこまでチェックするか](http://www.tokumaru.org/d/20090930.html)
  * [$_GET, $_POSTなどを受け取る際の処理](http://qiita.com/mpyw/items/2f9955db1c02eeef43ea)
  * [htmlspecialchars関数やhtmlentities関数で使用されるフラグの検証](http://qiita.com/mpyw/items/939c526dd5de6619b565)




# ドメインレベルでの対策を行っていない場合

**「出力時にエスケープ」** 1択です。他の選択肢は考えられません。著者の思いつきではなく、ここ数年万人によって当たり前のように言われ続けていることです。

>
> 【ユーザからの入力時】にサニタイズしてしまうと、HTML出力以外でサニタイズ前の文字列が必要になった際にhtmlspecialchars_decode()等で元に戻す必要があるため、やはり【HTMLへの出力時】がベストなのでしょうか？

その通りですね。他にも **エスケープ忘れ** や **多重エスケープ**
といったミスを防ぐ意図もあります。「格納時にエスケープ」という手段を採用している某日本の大手Q&Aサイトは、今までに私が確認できただけでXSS脆弱性を3回に加えて多重エスケープも同じ回数ぐらい発生させてしまっています。後者に関しては今も放置されている箇所があります。

また、エスケープされた状態だと **_「n文字以内でトリミングする」という処理を書くのが困難_**
になります。上で挙げたQ&Aサイトや某短文投稿サイトでもこれに関して、エンティティ表記されている部分が途中でぶった切られる問題も発生していたりします。

# ドメインレベルでの対策を行い、ユーザの自由なＨＴＭＬ記述を許可している場合

はてなブログやFC2ブログなどでは、 **「ログインした状態で何かするページ」** にはHTML記述を一切認めず、 **「記事を表示するだけのページ」**
ではHTMLの使用を認めています。 そもそもエスケープしていないことになりますね。 **_記事を表示しているページ上で直接コメント等が出来ない_**
ことに気付くと思います。はてなブログはインラインフレーム埋め込み、FC2ブログは別ページへの移動となります。

# どちらを選ぶべきか

セキュリティに関して十分な知識があり、ドメインを用意できるならこちらの選択肢もアリです。但し基本的にはやはり前者の「出力時にエスケープ」の方が選択されるべきです。

# `ENT_QUOTES` の必要性

シングルクオートで括られた属性内に表示する際には必須です。但し一般的にはダブルクオートで括る方が主流なので、デフォルトの `ENT_COMPAT`
が必ずしも悪いというわけではありません。思考停止したように `ENT_QUOTES` を採用する必要はないです。

但し…

  * 文字セットのデフォルト値がPHPのバージョンによって異なるという大きな変更が過去にあった
  * 使用頻度が多い割に関数名自体が長い

という背景も踏まえて、どうせなら

[code]

    function h($str) {
        return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    }
    
[/code]

という関数を作ってしまっておいてそれを流用する方が良いでしょう。

# `htmlspecialchars` と `htmlentities`

セキュリティ対策が目的であれば前者で十分です。

# 参考リンク

  * [「サニタイズ言うなキャンペーン」とは何か](http://takagi-hiromitsu.jp/diary/20051227.html#p02)
  * [「サニタイズ言うなキャンペーン」私の解釈](http://kmaebashi.com/zakki/zakki0042.html)
  * [htmlspecialcharsは不正な文字エンコーディングをどこまでチェックするか](http://www.tokumaru.org/d/20090930.html)
  * [$_GET, $_POSTなどを受け取る際の処理](http://qiita.com/mpyw/items/2f9955db1c02eeef43ea)
  * [htmlspecialchars関数やhtmlentities関数で使用されるフラグの検証](http://qiita.com/mpyw/items/939c526dd5de6619b565)

