APIアーキテクチャの基本形式
アプリケーションインタフェース(API)は、外部システムやクライアントに対して機能を提供するための通信規約です。現代の開発現場では主に以下の三つの設計スタイルが採用されています。
JSON-RPC/POSTリクエストベース
エンドポイントに対してペイロードを封入してリクエストを送信します。
POST /api/account/profile HTTP/1.1
Host: target-app.example.com
Content-Type: application/json
{
"target_id": 42,
"action": "retrieve_data"
}
RESTful API
URL構造そのものリソースを表現し、HTTPメソッドで操作種別を区別します。
ユーザー情報取得:
GET /api/v1/users/88 HTTP/1.1
Host: target-app.example.com
ユーザー属性更新:
PATCH /api/v1/users HTTP/1.1
Host: target-app.example.com
Content-Type: application/json
{
"display_name": "Jane Doe",
"contact_mail": "jane.d@example.com"
}
GraphQL API
単一のエンドポイントに対してスキーマ準拠のクエリ文字列を送信し、必要なフィールドのみを取得します。
POST /graphql HTTP/1.1
Host: target-app.example.com
Content-Type: application/json
{
"query": "{ user(id: 88) { id, display_name, contact_mail } }"
APIセキュリティ評価の焦点
APIに対する脆弱性評価は、主に「公開仕様に反する不正なロジック実行」と「非公開・未文書化されたエンドポイントへの不正アクセス」に重点を置きます。これらを悪用されると機密データ漏洩や業務フローの改ざんなど甚大な被害につながります。評価時は以下の要素を体系的に検証します:
- 必須/任意パラメータの扱いと入力検証ルール
- 許容されるHTTPメソッドおよびコンテンツタイプ(Content-Type)
- レート制限(Rate Limiting)と認証/認可メカニズム
- エラーレスポンスに含まれる情報漏洩リスク
HTTPメソッドとコンテンツタイプの実践的考察
プロトコルバージョンに関わらず、適切なメソッド選択はセマンティックな正当性を担保します。
- GET:安全かつ冪等なリソース取得専用
- HEAD:GET同等のヘッダー情報を取得しますが、ボディは送信しない
- POST:サーバー状態を変動させるサブミッション処理
- OPTIONS:ターゲットリソースがサポートする通信オプションの照会
- PUT:既存リソースの完全置換または新規作成
- DELETE:指定リソースの削除
- PATCH:リソースの一部のみを更新
- TRACE/CONNECT:診断用トンネル確立(本番環境では無効化推奨)
コンテンツタイプごとに期待されるデータ構造が異なります。代表的なものは以下の通りです:
application/json:構造化データ送受信の標準形式text/html:ブラウザレンダリング対象のマークアップapplication/x-www-form-urlencoded:HTMLフォームの標準エンコードmultipart/form-data:バイナリファイル混在のアップロードapplication/xml:XMLドキュメント交換application/octet-stream:型指定なしのバイナリストリームimage/png/image/jpeg:画像メディア専用
PortSwigger演習ケーススタディ
Laboratory 1:ドキュメント依存型のエンドポイント横断
対象:既存仕様書に記載のある操作手順の逸脱
達成目標:指定ユーザーアカウントの削除
検証手順では、監視ツール内の履歴からPATCHメソッドによるプロフィール更新リクエストを特定します。次に当該リクエストのメソッドをDELETEに書き換え、管理者権限が必要な削除処理に転用を試みます。通常、PATCHで許可されたパスであってもDELETEメソッドが拒否されない場合、認証付きの削除が実現可能です。
Laboratory 2:サーバーサイドパラメータ汚染(クエリ文字列編)
対象:フロントエンドからの入力値がバックエンドの処理分岐にそのまま反映される現象
達成目標:管理者セッションの奪取後、標的アカウントを削除
パスワード再発行機能のリクエストをモニターし、fieldパラメータの値を変更した際のリダイレクト挙動を検証します。静的JSファイル/static/js/passwordResetClient.jsを解析すると、以下のような初期化ルーチンが確認できます。
function bootstrapRecoveryUI(initAction) {
const currentParams = new URLSearchParams(window.location.search);
const sessionToken = currentParams.get('security_code');
if (sessionToken !== null) {
window.location.replace(`/recover-account?token=${sessionToken}`);
} else {
document.getElementById('btn-submit-reset').addEventListener('click', triggerValidation);
}
}
bootstrapRecoveryUI();
このクライアント側の分岐ロジックを踏まえ、リクエストペイロードでfield=security_codeとするように調整します。これを適用して同様のPOSTリクエストを送信すると、サーバー側でもトークン認識フラグが有効になり、本来隠蔽されているリセットページへ誘導されます。その後パスワード変更手続きを経て標的ユーザーの削除を実施します。
Laboratory 3:未文書化エンドポイントの発見と悪用
対象:管理画面や開発用APIとして残っているが、一般公開されていない終端
達成目標:支払いなしで商品を購入
アプリケーション全体の操作を網羅した後、トラフィック履歴からGET /api/inventory/item/4/rate_check HTTP/2を発見します。OPTIONSメソッドで対応方法を照会するとGETおよびPATCHが許可されていることが判明します。さらにPATCHリクエストのボディに数値型の商品価格を上書きするペイロードを注入します。サーバーがフロントエンドの表示価格ではなく内部DBの定義値を参照している場合、0円または負の価格で決済処理が完了し、ラボをクリアできます。
Laboratory 4:マスアサインメント(過剰代入)の活用
対象:リクエストボディ内に隠蔽フィールドを含められる際、バックエンドが不要なキーまで連想配列にマージしてしまう現象
達成目標:割引適用後の低額で購入
カートからチェックアウト流程を追跡すると、POST /api/process/payment HTTP/2にて以下の構造が送信されています。
{
"cart_snapshot": [
{"sku_code": "55", "count": 2}
]
}
このリクエストに"applied_discount_percent": 95といった計算上不要なキーを追加して送信します。フレームワーク側が入力バリデーションを経ずにモデルオブジェクトに直接束縛している場合、サーバーサイドの計算ロジック上で割り当てられた値が採用され、正常な決済フローを迂回して購入が成立します。
Laboratory 5:RESTパス内におけるサーバーサイドパラメータ汚染
対象:URLパス部分に変数が埋め込まれ、ハッシュ記号などを介した末尾オーバーライドが可能になる現象
達成目標:adminアカウントのパスワードリセット実行
クライアント側の実装をトレースすると、ログイン名部分がURLパスに連結される構成が推測されます。また、管理向けAPIパターンが/api/internal/v2/accounts/{identifier}/attribute/{attr_type}であることが判明しました。ここで#記号を含むパストラバーサル的な文字列を組み込み、リダイレクト時の振る舞いを欺きます。
例えばidentifierにadministrator/attribute/passwordHash%23を設定します。ブラウザのURL処理系では#以降がクライアント側にのみ渡されるため、実際にサーバーへ到達するのはadministrator/attribute/passwordHashとなります。これが意図した属性名の分岐をトリガーし、リセットトークンを取得可能になります。取得後は同一のメカニズムで認証情報の書き換えを実行し、標的アカウントを削除します。
API脆弱性対策ガイドライン
- システム設計の初期段階からセキュアコーディング基準と暗黙的拒否ポリシーを導入する
- サードパーティや検証チーム用の公式ドキュメント以外にエンドポイントを公開しない
- 包括的な攻撃表面積把握のため、テスト用エンドポイントも適切に文書化する
- 各APIに対し許可するHTTPメソッドを厳格にフィルタリングする
- 受信データと出力データをスキーマベースで検証し、予期せぬ形式のパッケージを即座に破棄する
- エラー情報は抽象化した統一言語に統一し、スタックトレースやDB構造を外部に出さない
- レガシー版APIも含め、すべてのバージョン階層に対して同等のセキュリティ制御を適用する
- リクエストオブジェクトのマッピング前にホワイトリスト方式で受け付ける属性を固定し、ブラックリスト方式の穴を利用したマスキュームを防ぐ