Hatena::ブログ(Diary)

ockeghem(徳丸浩)の日記 このページをアンテナに追加 RSSフィード

[PR]WAFの導入はHASHコンサルティング
 | 

2008-11-10 「はじめてのPHPプログラミング基本編5.3対応」のゆるいところ(2)

Shift_JISを利用することの是非 Shift_JISを利用することの是非を含むブックマーク

 前回に引き続き、はじめてのPHPプログラミング 基本編5.3対応のゆるいところ第二段は、文字エンコーディングについてだ。

 本書は、文字エンコーディングとしてShift_JISを採用している。しかし、本家から配布されているWindowsバイナリPHP処理系は、「--enable-zend-multibyte」というオプションが設定されていないため、2バイト目が0x5Cで終わる文字が正しく扱えない。このため、以下のPHPスクリプトはエラーになる。いわゆる5C問題である。著者には、ブログのコメントとして確認した。

<?php
    $a = "表";
?>

 文字列リテラルを"表\"としてやればエラーは回避できるが、わずらわしいし、第一みっともない(前世紀のスクリプトみたいだ)。

 やはり、ソースコードEUC-JPUTF-8で記述すべきだったと思う。前に取り上げたPHP×携帯サイト デベロッパーズバイブルの方は、携帯電話向けサイトで入出力にはShift_JISを用いるにも関わらず、内部コードとしてはEUC-JP(本の中では「EUC」と記載)を使うよう勧めている。そうするべき理由はあまり明確に書いていないが、実用的ではある。

 さて、ソースコード上の5C問題は、通常直接的には脆弱性とはならないが、Shift_JISを使うとなるとやはり脆弱性が気になる。本書の場合はどうだろうか。

 私がさくっと試した範囲ではXSSなどの「貫通」はできなかった。しかし、本の説明には危なっかしいところもある。以下のような箇所だ。

(htmlspecialcharsは)通常は第2引数まで指定すればほぼ問題ありませんが、念には念を入れるのであれば第3引数(文字エンコーディング)まで指定した方が良いでしょう。

「はじめてのPHPプログラミング基本編5.3対応」P203より引用

 「念には念を入れるのであれば」とあるが、どのような場合に「念を入れる」べきかの説明はない。正解は、「第3引数は常に指定すべき」である。一方、私が調べた範囲では貫通できなかったと書いたが、調べてみると、php.iniに以下の設定があるかららしい。

mbstring.encoding_translation = On

 この設定がOffの場合は、半端な0x81を用いて貫通が可能となった。mbstring.encoding_translationがOnの場合は、HTTPリクエストの文字列から、内部コードへの自動変換がされる。この場合は、Shift_JISからShift_JISへの変換だが、その過程でShift_JISとして無効な文字を除去するらしい。

 しかし、セキュリティの条件がmbstring.encoding_translationの設定に依存してしまうのは危険だと思う。この設定はOffにした方がよいという指摘もあるし、そもそも文字エンコーディングの妥当性をチェックする目的の設定ではないので、もっと明示的に文字エンコーディングのチェックを入れるべきだと思う(mb_check_encoding関数を用いるとよい)。

徳丸からのお勧め

arrayarray 2008/11/16 13:48 テストしましたがPHPに元々入っているhtmlspecialcharsに関してはSJISを第三引数に指定しても全く意味がないようです。
SJISとして認識できない半端文字の場合はSJIS指定しても貫通する様子なのですがどうでしょう。

mb_convert_encodingで明示的に文字コードをしていすればマップに無い文字を完全に消してくれますが、html_special_charsにその様な機能は無い様ですが。

mb_check_encodingはmb_substitute_charの設定に依存しているので、mb_substitute_charもセットしないと意味がないと思いますがどうでしょう。

文字チェックだけしたい場合はスクリプト内でsubstitute_charを設定した上でmb_convert_encoding前と後を比較した方が依存しません。

DB側から見た場合、SJISは避けた方が無難と思いますが、現状PHPでUTF-8を効率よく正規化する方法は無い様なので、EUC-JPが一番無難と思うのですがどうでしょう。

ここら辺が良く分からないので徳丸様のお勧めに関して解説お願いしますm(__)m

ockeghemockeghem 2008/11/16 20:02 arrayさん、色々検証いただいたようでありがとうございます。
私の基本姿勢は、プログラムは意味的に正しいように書こうというものでして、XSSとかSQLインジェクションなどはそれだけで大半が防げるはずなのです。それで防げないのは、ブラウザのバグ対策など、本来アプリケーションの責任でないものが該当します。
htmlspecialcharsの第三引数を指定しない場合、ISO8859-1(Latin-1)が仮定されるとのことですので、日本語を使う場合、それは意味的には正しくないことになります。現状、htmlspecialcharsに不正な文字エンコーディングを検出・除去する機能はありませんが、検出することは理論的には可能ですし、第三引数を指定して害はないので、現状でも指定しておくべきでしょう。アプリケーションプログラマが、マルチバイト関数の実装の詳細を知っている必要はないはずで、淡々と正しい引数指定をしていけば正しいプログラムができあがるというのがあるべき姿だと思います。
コメントの後半に書かれていることは、私の知らないことが多くありますので、私の方が勉強になりました。ただ、「UTF-8を効率よく正規化する方法」は必要なくて、冗長なUTF-8があれば、積極的にエラーにすべきだと思います。
しかし、PHPのソースまで読まないとPHPを正しく使えないというのでは困りますね。まずはドキュメントの整備が必要なのだなという思いを強くしました。

 | 
Google
Connection: close