PHP セキュリティ解説 · 防御向け
PHP オブジェクトインジェクションとは?直し方
利用者が操作できるデータを unserialize() に渡すと、PHP がどのオブジェクトを生成するかを攻撃者が選べてしまいます。PHP マニュアルもこれを明確に警告しています。
最終更新
どんな問題か
PHP は文字列をアンシリアライズするとき、記述されたオブジェクトを再構築し、__wakeup() や __destruct() などのマジックメソッドを呼ぶことがあります。文字列が Cookie、フォーム、API リクエストから来るなら、攻撃者はアプリやライブラリに読み込まれたクラスを選んでメソッドを連鎖させ、ファイル書き込みやコード実行につなげられます。MITRE では CWE-502(信頼できないデータのデシリアライズ)に分類されます。
見つけ方
- コード内の
unserialize(を検索し、各引数の出どころを追跡します。$_GET、$_POST、$_COOKIE、ヘッダー、アップロードファイル、利用者が書き込めるデータベースの値から届くなら問題です。 - サードパーティのプラグインや古いライブラリも同様に確認します。過去の CMS プラグインの公告の多くがオブジェクトインジェクションでした。
- セキュリティルール付きの静的解析(PHPStan、Psalm)や依存関係の監査(
composer audit)で既知の脆弱なパッケージを見つけられます。
直し方
- 信頼境界をまたぐデータには
json_encode()とjson_decode()を使います。JSON では PHP オブジェクトを生成できません。 - どうしても
unserialize()を使うなら['allowed_classes' => false]か短い明示リストを渡します。それでも PHP マニュアルは信頼できない入力を渡さないよう勧めています。 - クライアント側に保存するシリアライズデータは HMAC で署名し、デコード前に検証します。
- フレームワークとライブラリを更新し、既知のガジェットチェーンをなくします。
読み取り専用の確認と安全な書き方
# Find unserialize() calls that may receive request data (read-only)
grep -rnE "unserialize\s*\(" --include=*.php . | grep -vE "/vendor/|/tests?/"
// Safer: exchange data as JSON
$data = json_decode($input, true, 512, JSON_THROW_ON_ERROR);
// If unserialize() is unavoidable for trusted data, forbid objects
$data = unserialize($trusted, ['allowed_classes' => false]);allowed_classes => false で十分ですか?
オブジェクト生成を止めるので主なリスクはなくなりますが、PHP マニュアルは信頼できない入力のアンシリアライズ自体を勧めていません。既定は JSON が安全です。
PHP2Shell と関係がありますか?
ありません。PHP2Shell は PHP ランタイムの不具合で、オブジェクトインジェクションはアプリのコードの不具合です。PHP を完全に更新していても起こり得ます。
ほかの PHP の脆弱性の種類
- PHP ファイルインクルード(LFI/RFI)とは?直し方ファイルインクルードは利用者の入力が include や require のパスを左右すると起き、攻撃者はローカルファイルを読み(LFI)、allow_url_include が有効ならリモートのコードを実行できます(RFI)。
- PHP の SSRF とは?直し方サーバーサイドリクエストフォージェリ(SSRF)は PHP アプリが利用者の指定した URL を取得すると起き、攻撃者はサーバー経由で内部サービスやクラウドのメタデータに到達できます。
- PHP の XSS とは?防ぎ方クロスサイトスクリプティング(XSS)は PHP のページが利用者の操作できるデータをエスケープせずに HTML に出すと起き、攻撃者のスクリプトがほかの訪問者のブラウザで実行されます。
- phpinfo() の露出:なぜ問題か、どう直すか公開された phpinfo() ページは正確な PHP のバージョン、読み込まれたモジュール、ファイルパス、しばしば環境変数や秘密情報まで明かし、PHP2Shell のような脆弱性を狙う手がかりになります。
出典
外部リンクは本サイトの外に移動します。本サイトはエクスプロイトコードを掲載しません。
- unserialize() — PHP Manual
- json_decode() — PHP Manual
- PHP Object Injection — OWASP
- CWE-502: Deserialization of Untrusted Data — MITRE CWE