脆弱性の「盲点」を突く:ビジネスロジック欠陥を狩るレッドチームの視点
セキュリティ診断ツール(スキャナ)は優秀だが、万能ではない。彼らは「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点を自問自答するだけで、多くの重大なインシデントは未然に防げる。技術は常に進化するが、攻撃者の視点はいつだって「仕様の隙間」を狙っている。君たちの手で、その隙間を埋めていってほしい。
コメント