【実務・中級編】 Business Logic Vulnerabilities (ビジネスロジックの脆弱性) の特定 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

脆弱性の「盲点」を突く:ビジネスロジック欠陥を狩るレッドチームの視点

セキュリティ診断ツール(スキャナ)は優秀だが、万能ではない。彼らは「SQLインジェクション」や「クロスサイトスクリプティング」のような、いわば「文法の間違い」を見つけるのは得意だ。しかし、システムが意図した通りに動いているか、つまり「開発者が想定した業務フローの裏側に、別の顔が存在しないか」を自動的に判断することは不可能に近い。

今日は、我々レッドチームがペネトレーションテストにおいて、最も「美味しい」ターゲットとしているビジネスロジックの脆弱性について、泥臭い現場の視点から解説しよう。

—

1. なぜビジネスロジックは狙われるのか?

システム設計図と実装の間に生じる「解釈の揺らぎ」が脆弱性の温床だ。例えば、「割引クーポンを適用する」という機能において、コード上は正しく動いていても、「クーポン適用リクエストを送信した直後に、カート内の商品を入れ替えたらどうなるか?」といった境界条件は、仕様書には書かれていないことが多い。

攻撃者は、この「仕様の隙間」を縫う。ツールは「正常なリクエスト」を繰り返すだけだが、レッドチームは「本来ありえない順序のリクエスト」や「ステート(状態)を無視した操作」を試行する。

—

2. 典型的な攻撃シナリオ:価格操作(Price Manipulation)

最も古典的かつ破壊力が高いのが、決済プロセスにおける価格の改ざんです。

攻撃手法:

クライアントサイドで計算された金額や、一度確定したカートの状態を、決済直前のパラメータ書き換えによって操作する。

実務的な脆弱コード例 (PHP)

以下は、脆弱なチェックアウトプロセスの典型的な実装例だ。

<?php
// 脆弱な実装:クライアントから送られてきた価格をそのまま信じている
$item_id = $_POST['item_id'];
$price = $_POST['price']; // ここを改ざんされる!
$quantity = $_POST['quantity'];

// データベースの正しい価格を参照していない
$total = $price * $quantity;

// 決済処理へ...
process_payment($total);
?>

このような実装が放置されているシステムは、100万円の高級時計を1円で購入されるリスクを抱えている。

—

3. 完全防御のためのセキュアな実装

ビジネスロジックの不備を防ぐ唯一の鉄則は、「クライアントからの入力はすべて疑い、必ずサーバー側の信頼できるソース(データベース)を再参照すること」だ。

修正後のセキュアな実装 (PHP)

<?php
// 信頼できるソースから価格を取得する(クライアントの入力はIDのみ受け取る)
$item_id = filter_input(INPUT_POST, 'item_id', FILTER_SANITIZE_NUMBER_INT);
$quantity = filter_input(INPUT_POST, 'quantity', FILTER_SANITIZE_NUMBER_INT);

// DBから最新の正当な価格をフェッチ
$stmt = $pdo->prepare("SELECT price FROM products WHERE id = :id");
$stmt->execute(['id' => $item_id]);
$product = $stmt->fetch();

if (!$product) {
    die("商品が見つかりません。");
}

// サーバー側で計算を完結させる
$total = $product['price'] * $quantity;

// 決済処理...
process_payment($total);
?>

このように、クライアント側はあくまで「リクエストを送る」だけであり、決定権をサーバー側に固定することで、ロジックの改ざんを無効化できる。

—

4. インフラレベルでの防御(WAFの活用)

ビジネスロジックの脆弱性をピンポイントで防ぐのは難しいが、異常なリクエストを排除する「振る舞い検知」は有効だ。Nginxの limit_req や AWS WAF のレート制限を活用し、短時間に連続してカート操作を行うようなボット的挙動を遮断する。

Nginx 設定例(レート制限)

# 1秒間に1回以上のカート操作リクエストを制限する(ブルートフォース防止)
limit_req_zone $binary_remote_addr zone=cart_limit:10m rate=1r/s;

location /api/cart/ {
    limit_req zone=cart_limit burst=5 nodelay;
    # ... backend logic
}

—

5. まとめ:レッドチームからの提言

ビジネスロジックの欠陥を見つけるには、ツールを回すよりも「もし自分が悪意のあるユーザーだったら、この機能をどうやって『ズル』して使うか?」という想像力が必要だ。

1. ステートの検証: 処理の順序(例:ログイン→カート追加→決済)は、どこかでスキップできないか?
2. パラメータの信頼性: 隠しフィールドやクライアント送信データだけで完結している処理はないか?
3. 認可の二重チェック: 権限があるかどうかのチェックは、APIの入り口だけでなく、DB更新直前でも行われているか?

開発中のコードをレビューする際、この3点を自問自答するだけで、多くの重大なインシデントは未然に防げる。技術は常に進化するが、攻撃者の視点はいつだって「仕様の隙間」を狙っている。君たちの手で、その隙間を埋めていってほしい。

コメント

タイトルとURLをコピーしました