PHP本体のセキュリティ関連バグは多い?
PHP本体のバグはほかの言語(Perl、Ruby、Pythonなど)に比べ体感的に多いと思いませんか? 実際にPHP本体のセキュリティ問題は突出して多くレポートされています。今回はPHP本体にセキュリティ関連バグが多いとされる理由を考察してみます。
セーフモード(safe_mode)機能
safe_mode関連のバグは、PHP本体のセキュリティ問題として最も多くレポートされる問題です。しかし、実際にはsafe_modeは確実なセキュリティ対策を行うための機能ではありません。よくある誤解はsafe_modeについて「共有サーバ環境でユーザがほかのユーザのファイルを参照できなくする機能」であるという勘違いです。safe_modeは同じサーバ上のほかのユーザファイルを盗み見ようとする悪意があるスクリプトから「防御」するための機能ではなく、善良なスクリプトにバグがあった場合でも意図しないファイルにアクセスされ「づらく」する機能です。
safe_mode機能は悪意があるスクリプトからファイルを保護するには不十分極まりない機能です。PHPは実行環境には仮想マシンを利用していますが、ファイルなどのI/OはすべてOSの機能に頼っています。仕組み的にも安全性を十分に確保したサンドボックスを構築できませんし、PHPプロジェクトとしてもそれを目指していません。safe_modeは「サンドボックスを提供する安全なモード」ではなく、「バグがあるスクリプト用のフェイルセーフを提供するモード」です。PHP6からはsafe_modeは廃止されます。
safe_modeチェックに不備があると、確かにセキュリティ上の不備があったといえますが、これを現実社会に当てはめるならば「家の周りの塀に穴や隙間があって敷地に侵入可能」である問題と考えられます。一般の家の塀は外部からの侵入を完全に防ぐことを目的に作られていません。PHPのsafe_modeも「一般の家の塀」レベルのセキュリティを提供する機能なのです。
拡張モジュール
PHPのソースには多くの拡張モジュールが添付されているので、バグが含まれる可能性も高くなります。通常のプログラミング言語の場合、ライブラリ等に不具合があっても「プログラミング言語に不具合があった」と認識されません。しかし、PHPの場合は一緒に配布されている拡張モジュールの不具合も「PHP本体の不具合」としてレポートされる(少なくとも多くの方にとってはPHP本体の不具合として認識されていると思われる)場合が多くあります。
例えば、セッション管理を行うモジュールには数々のセキュリティ上の不具合がありますが、ほかのスクリプト系の言語では「言語の問題ではなくライブラリの問題」とされます。しかし、PHPの場合は言語とモジュールが一つのソースとして配布されているので「PHP 5.2.1のセッションモジュールにはSession Adoptionの脆弱性がある」と記述されます。
ほかのスクリプト系言語と違い、モジュールの不具合も言語本体の不具合としてレポートされるのはソースの配布形式にも問題があります。モジュールのソースを別途に配布していれば「PHP Sessionモジュール 2.3.4にSession Adoptionの脆弱性がある」(実際に2.3.4というバージョンある訳ではありません)とレポートされ、言語本体に問題があると取られかねないタイトルにはならないです。
Web開発フレームワークとしてのPHP
PHPはほかの言語と異なり、Web開発のフレームワークとして誕生し成長してきました。ほかの言語ではライブラリ機能として実装されているHTTPフォームやファイルアップロード、様々なエンコーディング変換機能、メモリ制限機能などがPHP本体に取り込まれています。機能を追加するとバグが発生する可能性が高くなります。実際、ここで紹介した機能すべてにセキュリティ上の問題が発見・修正されています。
コーディングスタイル
古いPHPのソースコードは互換性があるデータ型であれば同じ変数に対して複数のデータ型を使っていました。さすがに最近のソースコードでは問題が少なくなってきていますが、このようなコーディングスタイルでは64ビットプラットフォームで問題が発生します。最近リリースされたPHP 4.4.6でもこれが原因で整数オーバーフローが発生していたので修正されました。
筆者はコードが記述されたマクロ、マクロを再定義するマクロが多すぎることも問題だと考えています。多すぎるマクロは可読性を低下させ、メンテナンス、特にコード監査を難しくさせます。マクロでコードを置き換えると、デバッガを使用してソースをステップ(1行)単位でトレースしている場合にマクロが1ステップとして実行され、デバッグが難しくなる問題もあります。PHPのソースには非常に多くのマクロが利用されており、インライン関数に書き換えたり、そのままコピーして利用したほうがよいと思われるマクロが多数あります。
PHP開発者の意識
すべてのメモリ関連問題、すべてのクラッシュは、セキュリティ上の問題となる可能性があり修正されるべき問題として対処しなければならない、と筆者は考えています。自分が攻撃コードを考案できなくても、ほかの人は攻撃コードを考案できるかも知れません。一つ一つは軽微な問題でも組み合わせて利用して重大なセキュリティ問題が発生したりします。互換性・拡張性を犠牲にしてでもセキュリティ上の問題を適切に解決しなければなりません。しかし、残念ながらPHPの開発者には同じ考えを持たない開発者もいます。昨年PHPソースコード監査の第一人者であるStefan Esser氏がPHPセキュリティレスポンスチームを去ったのは、PHP開発者のセキュリティ意識に失望したためです。
今月はHardened-PHPプロジェクト( http://www.hardened-php.net/ )のStefan Esser氏が中心となって「the Month of PHP Bugs」- MOPB( http://www.php-security.org/ )を開催しています。すべてのPHPユーザはどのような問題がPHPにあるのか(あったのか)知るべきと考え、Stefan氏の許可を得て筆者の個人ブログ( http://blog.ohgaki.net/ )で日本語に訳したバージョン( http://blog.ohgaki.net/index.php/yohgaki?cat=41 )を公開しています。翻訳に十分な時間を取れず不十分な箇所も多いですが、英語より日本語での情報がよい場合はご覧ください。MOPBによりいくつかの(PHP開発者には)長年の間知られていたセキュリティ上の問題も解決されることなりました。今後もPHP開発者のセキュリティ意識も改善されると思われます。Stafan氏の我慢強い努力の成果といえます。
PHPは使いづらい!?
「PHPはセキュリティバグが多くて使いづらい」と感じているシステム管理者も多いと思います。
バージョン間での互換性に問題があることがあります。よくある問題は「バージョンAからバージョンBにすると、モジュールXの不具合は解消されるがモジュールYに問題が発生する」などです。複数の機能を単一のディストリビューションとして配布しているため、この種類の問題は頻繁に発生しがちです。PHPのモジュールは「モジュール」ですから、PHPとモジュールのAPIに変更がなければ「入れ替え」て使用することができます(コンパイルしなければならないので、RPMなどバイナリ化したモジュールを入れ替えても使えません)。モジュールのセキュリティ状態に注意して、入れ替えを行えばバージョンアップも容易になります。
一概にセキュリティ上の問題が多くレポートされているから危険、レポートされていないから安全、とは言えません。例えば、Mac OS Xはセキュリティ上の問題が少ないとされてきましたが、「the Month of Apple Bugs」( http://projects.info-pull.com/moab/ )により、数多くのQuickTimeバグなどで神話に過ぎないことも実証されました。最も怖いのはセキュリティ上の問題が存在するにも関わらず、その存在がユーザに知られないことです。
PHPの場合、「言語、Web開発の基本フレームワーク、よく利用される拡張機能」が一体となって配布され、セキュリティ情報もまとめて入手可能であること、Hardened-PHPプロジェクトのようにコードの監査と安全性向上を目的としたプロジェクトが存在することは、ユーザにとって大きなメリットです。