allow_url_fopenは無効に設定

Webサイト構築で注意しなければならない箇所は決まりきっています。PHPのiniオプションでかなり危険な設定ですがデフォルトで有効かつシステムレベルでのみ設定変更可能なiniディレクティブ、allow_url_fopenがその内の一つです。

このオプションが有効な場合、ほとんど全てのファイル関数でローカルファイル以外にURL(HTTP、FTP)を利用しリモートファイルを読み込みます。インクルード系の関数も同様です。

include('http://code.example.com/script.php');

と記述するとリモートサーバに保存されたスクリプトを読み込んでローカルホストで実行します。先日のphpbbのセキュリティーホールはこのタイプのミスだったようですね。このタイプのセキュリティーホールは【緊急より更に上】レベルの重大な問題です。しかし、何度も同じようなミスは色々なプログラムで発生しています。

私も機会がある度にこのオプションの危険性について紹介していますがどうも不毛な気がしてきました。この際、この機能はデフォルト無効、有効にした場合もallow_url_fopenは利用可能なサーバを列挙可能なように仕様を変更した方が良いですね。

パッチの作成は簡単なのですが…

追記:
allow_url_fopenがINI_SYSTEMである件を「あれ?」と思ってちょっと調べて見るとPHP4.3.4からINI_ALLだったものがINI_SYSTEMになっていますね。この変更、かなりまずい変更だと思います… サーバ管理者がallow_url_fopenの動作を制限できるようにするなら、sefe_mode_url_fopen等のディレクティブを新たに作り管理者が制限できるように実装するべきです。INI_SYSTEMに変えてしまうと共有サーバでは設定変更ができない可能性があります。スクリプト中の特定箇所でのみallow_url_fopenを有効にする、などの現実的な対処も行えなくなります。どうしたものか…

session_regenerate_idの使い方に注意!

久しぶりにPHP-users MLを見るとsession_regenerate_id関数が「古いセッションIDに関連したセッション情報を削除しないのは困るよね」と投稿がありました。

バグレポートではBogus(バグじゃない)というステータスになっていました。確かにsession_regenerate_id関数は新しいセッションIDを生成する為の関数として追加されました。新しいセッションIDを作れば仕様上は問題ない、と主張できるかもしれません。しかし、アプリケーションの作り方によってはセキュリティ上の問題を発生させる原因になるので変更するべきですね。

セッションモジュール、セーブハンドラモジュール、シリアライザモジュールの各グローバル変数がマクロでアクセスされる作りになっています。(セッションモジュールは更にサブモジュールと持つ構造になっています。随分前ですがWeb+DB Pressに書いた通りです。興味のある方はどうぞ。)さらに引数などもマクロで定義されているため、初めて読むプログラマには非常に分かりづらいソースになっています。

PHPセッションモジュールのソースを読んだ事がある方なら分かりますが、グローバル変数を使用している、今回の場合はPSマクロで利用するグローバル変数、のでセッションID、PS(id)、を保存しないとならないように思えます。
# 今思いつきましたが、PS(data)にempty_stringを入れて
# おけばOKなような気がします。

session_destory関数にはバグがあるようでセッション情報は空になりますが、ファイルをunlinkしたいようなコードになっているのですが…、unlinkされていません。XFSなど、ディレクトリエントリにB-Treeを使用しているファイルシステムでは大量のファイルがあっても性能上や使用上問題ありません。個人的には50万ファイル(50万セッション)までファイル作成してベンチマークしてみましたが、性能は全く変わりませんでした。

ext3を利用している場合、2の問題で困る可能性があります。一つはinodeの枯渇ともう一つパフォーマンスの低下です。デフォルトではinodeが枯渇する可能性は大きいと思います。DoSの原因にもなるので注意しましょう。Linuxの場合、ディレクトリエントリはキャッシュされているので多数のファイルがある場合でもかなり良い性能ですが、それでも何十万ファイルレベルになると遅くなります。

セッション管理は有効期限を0に設定したセッションクッキー(ブラウザの終了と同時に削除されるクッキー)を利用し、自動再ログインなどの仕組みはアプリケーションでセキュリティ上の問題が許容される取り扱い方法を独自に実装する方が良い、と考えています。

もし有効期限が長いセッションIDを利用してログイン状態を保ち、セッションIDの再生成でXSSのリスクを軽減されている場合はsession_destroyを使用してセッションの削除を忘れないようにしなければなりません。ご注意ください。

PHPポケットリファレンスの改訂版にご意見ください

PHP5に対応したPHPポケットリファレンスの改訂版を執筆中です。アマゾンのレビューでは「サンプルスクリプトがサンプルになってない」と指摘も頂いています。

Wikiにも書いたとおり、サンプルスクリプトらしいコードを目指して書いていません。PHPは言語仕様と同じく関数仕様の記述も結構曖昧なこともあり、結局どういった入力の時にどのような動作や戻り値になるのか実行してみないと分からない事がよくあります。エラーが発生した場合、まっとうなシステムであればエラー処理をしなければならいですが、どの様な場合にエラーが発生するのか調べる、もしくは覚えていないと品質の高いシステムは作れません。この本ではシステム構築上、特に問題になりそうなエラー発生状態は分かるように書いたつもりです。

あまり時間も無いのでどこまでご意見を反映できるかわかりませんが、ここが不満、ここを改善した方が良い、などご意見を頂ければ助かります。もちろんメールで送って頂いても大丈夫です。よろしくお願いいたします。

はじめてのPHP言語プログラミング

まえにも書きましたが「はじめてのPHP言語プログラミング」という本を書きました。5月10日発行となっていますが、昨日からアマゾンでも買えるようになったようです。

Webサイトを作る為の入門書ではなく、PHPを習得する為の入門書として書いたつもりです。思い切って解説なしの部分も多々ありますが、プログラム経験者の方でこれからPHPを習得する方には適している本になったと思います。プログラミング初心者の方も、説明不足な部分がありますが、あまり問題無く読めると思います。もし読まれたら、メール、ブログ、Wiki、どこでも構いませんのでコメントを頂ければありがたいです。

PHPポケットリファレンス
は書きっぱなしでサポートページさえ作らずでしたが、今回からはサポートページも作って対応する予定です。

# データベースの説明にPostgreSQLが多く出てくるのは趣味です。
# 売れる本を狙うならMySQLなのかも知れませんが…

はじめてのPHP言語プログラミング

まだいつ発売になるか私も知りませんが「はじめてのPHP言語プログラミング」(技術評論社)というタイトルでPHP入門書を書きました。4月末から5月に書店に並ぶと思います。

Webサイト構築の為の入門書ではなくプログラミング言語の入門書、読み終わった後もリファレンスとして使える本になるように書いたつもりです。どちらかと言うと既にプログラミング言語を習得されてPHPもマスターしたい方向けかもしれません。320ページで全て説明するのは難しく、ばっさり説明を省略している部分もありますが、言語仕様の解説部分では出来るかぎり妥協しないようにしています。どんな本を書く場合も同じと思いますが「自分が欲しい」と思える書き方、内容になったと思っています。

宣伝にはまだ早すぎですが、書店で見掛けたら買ってください 🙂

PHPで巨大ファイル

PHPで巨大なファイルを取り扱うことが出来るか下調べしました。PHP内部的にPHPストリームと言う仕組でファイル等を取り扱う事が可能になっているのですが、ファイルヘのアクセスに符号付き32bit整数を使っています。このため扱えるファイルサイズが2GBに制限されています。

タイムリーな事にPHP-INTERNALメールリストでPHPストリームのコードを書いたWez氏がint64_t対応を行う旨の投稿をしていました。待っていれば2^63-1バイトまでのファイルが取り扱える様になるようです。

HTTP Response Splitting Attack: PHPの場合

ここの日記にも書いたHTTP Response Splitting Attackの対策がPHPでも取られるようです。

header(“bad-header: This is bad header\r\n but having CR/LF in a haeder is allowed by the standard in some case.”);

上記のヘッダが送られた際に\r\nを自動削除可能な設定が追加されます。ただし、\r\nがヘッダ中に現れる事は標準で認められいいますが、パッチを適用したPHPの場合は拒否&警告エラー(php.ini設定のデフォルト値になる)が発生します。もちろん「不正なユーザ入力対策は万全」というサイト向けではそのままCR/LFを送ることも可能です。次のPHPリリース時には取り込まれていると思いますが、仕様が変わっているかも知れないのでChangeLogなどで確認する必要があります。

未対策のアプリがあるサーバはエラーハンドラ(必ず作ってますよね。PHPプログラマの方!)で処理するだけです。普通にエラー処理しているPHPアプリケーションならPHP本体にパッチを当てるだけで完了です。

「まるごとPHP」

最初のセクションの部分に「まるごとPHP」著者の一人である月宮さんがツッコミを入れられてますね。ちょっと辛口のコメントです。初心者向けに記述するのは難しいですね。私も気を付けないと… (私も「まるごとPHP」にセキュリティー関係でほんの少しだけ書いています)

月宮さんの日記のコメントにも書きましたが、PHPでは明示的にリソース(DB接続・ファイル)や変数を開放する必要がほとんどありません。Webプログラムでは明示的に開放しない方が良いくらいです。例えば、DBの永続的接続を使っていない場合、システム負荷を上げるだけで役立つ事はほとんどありません。永続的な接続を利用している場合、データベース接続を切断する関数を呼ぶと役立つ事は一切無く無駄なCPUリソースを消費するだけです。