はじめに
「web99」という言葉を見て、何のことだろうと疑問を持っていませんか? 本書はその疑問に答えるために書きました。主にCTF(Capture The Flag)やサイバーセキュリティ学習で使われる問題番号としてのweb99の意味を解説し、PHPのin_array関数に関わる弱比較の脆弱性をやさしく説明します。さらに、実務やCTFでの危険性、具体的な対策、学習で押さえておきたいポイントまで整理しています。
対象はこれからセキュリティを学ぶ方や、CTFに挑戦したい初中級者です。専門用語はできるだけ控え、具体例で理解を助けます。本章では本稿の目的と構成、読み進め方を案内します。各章は独立して読めますが、順に読むと理解が深まります。
この記事を読むと、web99が何を指すかが明確になり、PHPの弱比較が引き起こす問題の本質と、実践的な対策の方向性がつかめるはずです。どうぞ気軽に読み進めてください。
web99とは何か?
概要
「web99」は、CTF(Capture The Flag)などで出題されるWebセキュリティの問題番号の一つです。特にPHPの比較や関数の挙動に起因する脆弱性を学ぶための実例として使われます。初心者が言語の仕様で起こる落とし穴を体験するのに適しています。
何が学べるか
この問題を通して学べる主な点は、言語の比較ルールと関数の引数の意味です。具体的には「比較がどのように行われるか」「厳密な比較と緩やかな比較の違い」「関数に与えるパラメータで挙動が変わること」を理解できます。
簡単な例(イメージ)
PHPでは文字列や数値の比較で意図しない一致が起きます。たとえば、文字列が数値扱いされて等しいと判断される場合があり、それを悪用して条件を通してしまうことがあります。in_array関数は第三引数に注意すると安全性が高まります。
使われる場面
CTFでは学習用の問題として、実務では設定の甘さを確認するための教材として扱われます。実際のアプリでは、型を明示するなどの対策が重要です。
PHP in_array関数の弱比較脆弱性
概要
PHPのin_array($needle, $haystack)は、第三引数にtrueを渡さないと”==”(弱比較)で判定します。弱比較は型を自動変換するため、意図しない一致が起きやすいです。web99ではこれが問題の核になっています。
仕組みの簡単な説明
弱比較では文字列が数値として扱われることがあります。たとえば”0e123456″のような文字列は数値0に見なされ、”0″と等しいと判定されます。これはPHPの型変換による振る舞いです。
具体例
危険性
攻撃者は”0e…”の形を使って、ホワイトリストや認証のチェックをすり抜けられます。期待した値と異なる入力でも一致してしまうため、認可ミスや情報漏えいにつながります。
簡単な対策
in_arrayでは第三引数にtrueを渡して厳密比較(===)を使ってください。さらに入力の型を明示的に検証することをおすすめします。
CTFや実務での危険性
CTFでの典型例
CTFでは、in_arrayの弱比較を狙った問題がよく出題されます。出題者は入力の型や値を工夫して、意図せず一致するケースをつくります。参加者はその性質を利用して認証バイパスやフラグ取得を行います。明確な例を示すと、空文字や数値の文字列が意図せず一致することがあります。
実務でのリスク
実際のWebアプリでも同様のミスが起こります。たとえば、許可されたユーザーIDやAPIトークンを配列で管理し、in_arrayでチェックすると、弱比較により誤って許可される可能性があります。クッキーやリクエストパラメータをそのまま比較すると攻撃を受けやすくなります。
想定される影響
不正ログイン、権限昇格、個人情報の漏えいといった深刻な被害につながります。被害は限定的でなく、運用停止や信頼失墜にも発展します。
開発時の注意点(次章への導入)
簡潔な対策として、in_arrayの第三引数にtrueを指定する(厳密比較)ことが有効です。さらに入力検証や型の明示を行うことで、被害を防ぎやすくなります。
第5章: 対策とセキュリティ実践
はじめに
脆弱性を防ぐには、コードの書き方と運用の両方で対策が必要です。ここでは実践的に取り組める手法を具体例とともに説明します。
1. 厳密比較を使う
PHPではin_array($needle, $haystack, true)のように、第3引数にtrueを渡して厳密比較(型も含める)を行ってください。例:
if (in_array($input, $allowedValues, true)) {
// 許可された値として扱う
}
また比較には==ではなく===を使って、型の違いで誤判定しないようにします。
2. 入力検証とホワイトリスト
受け取る値の型や形式を明確にし、ホワイトリスト方式でチェックします。数値はキャストして範囲を確認する、文字列は正規表現やfilter_varで検証するなどを習慣にしてください。
例: 整数のIDを受け取る場合は(int)$idでキャストし、負の値や極端な値を弾く処理を入れます。
3. テスト・レビュー・自動化
ユニットテストや結合テストで、緩い比較に起因するケースを含めてテストを作成してください。コードレビューで第三者にロジックを確認してもらうとミスが減ります。CIで静的解析ツールやセキュリティスキャンを回すと早めに検出できます。
4. 教育と実践訓練
CTFや脆弱性演習をチームで行い、実際に弱点を見つけて修正する経験を積んでください。小さな仕様の違いが大きなリスクになることを体感できます。
5. 運用面の対策
不正アクセスのログを詳細に残し、異常があれば通知する仕組みを整えます。依存ライブラリやランタイムは定期的にアップデートして、既知の脆弱性を放置しないようにします。
まとめと学習ポイント
web99のような問題は、言語に内在する「型の違い」と「比較演算子の仕様」を正しく理解することの重要性を教えてくれます。特にPHPでは弱比較(== や in_array のデフォルト挙動)が意図しない真偽評価を招きやすく、入力検証が不十分なまま使うと脆弱性につながります。
- 基本の理解を優先する:型変換や比較の挙動をドキュメントで確認し、実際に小さなサンプルで挙動を確かめます。
- 厳密比較を使う:PHPでは===やin_arrayの第三引数にtrueを指定して厳密比較を行います。これだけで多くの誤判定を防げます。
- 入力のホワイトリスト化:受け付ける値を明示的に限定し、不正な型や値は早期に排除します。
- ロギングとテスト:エッジケースを含む単体テストとログで問題を早期検出します。自動解析ツールも有効です。
- 教育とレビュー:CTFの学習者だけでなく実務チームも定期的に脆弱性を学び、コードレビューで指摘し合います。
今回の問題を通して、言語仕様を軽視しないこと、そして日常の開発でセキュアコーディングを習慣化することが最も大切だと理解できるはずです。今後も小さな違いに注意を払いながら学習と実践を続けてください。