Webアプリ脆弱性とAPI認可

Aug 4, 202525 min

この章の到達目標

HTTPリクエスト、プログラム、DB構造、応答結果を読んで、どの処理が欠落しているか を特定し、修正方法を記述できるようにする。

2023年度のXSS、2024年度のWebスキミング、2025年度のCSP・権限昇格と直接つながる、最も出題が多いテーマである。


1. 用語一覧

優先用語・技術科目Bで押さえるポイント
AIDOR / BOLAオブジェクト単位の認可不備、他人のデータへのアクセス
ABFLAAPIの機能単位の認可不備、管理機能の不正実行
A水平・垂直権限昇格同じ権限の他人へのアクセス/上位権限の取得
ASQLインジェクションSQL構文の改変、プレースホルダーによる防御
AXSS(反射・格納・DOM型)スクリプトの混入位置・実行経路・対策の違い
ACSRF認証済みブラウザーに意図しない操作を実行させる
ASSRFサーバを経由した内部API・メタデータサービスへのアクセス
ACSPscript-src、nonce、hash、許可オリジン、制約と回避条件
ACookie属性HttpOnly、Secure、SameSite、Domain、Path
Aセッション管理セッション固定化、乗っ取り、ID再生成、有効期限
A認証と認可ログイン成功と対象リソースへのアクセス許可の違い
Aサーバ側認可検証所有者ID・所属組織・権限をサーバ側で照合
A入力検証・出力エスケープ入力の妥当性と、HTMLなどの出力文脈に応じた処理
BJWT署名検証、iss、aud、exp、alg、鍵の管理
BCORS / SOPブラウザーのオリジン間アクセス制御と限界
Bクリックジャッキングframe-ancestors、X-Frame-Options
BOSコマンドインジェクションシェルのメタ文字、コマンド引数の扱い
Bパストラバーサル../ などによる意図しないファイル参照
Bファイルアップロード脆弱性MIME・実体検査、保存先、実行禁止
BWebスキミング決済画面改ざん、カード情報の外部送信
BXXEXML外部実体の悪用、ファイル参照やSSRF
BAPIレート制限ブルートフォース、列挙、大量取得への対処
Bマスアサインメントリクエストの余分な属性による権限・状態変更
BHTTPリクエストスマグリングプロキシとバックエンドのメッセージ解釈差
Bキャッシュポイズニングキャッシュキーの不一致、応答の汚染
BセキュアSDLC脅威分析、コードレビュー、セキュリティテスト
BSAST / DAST / SCAソース解析・動的診断・依存ライブラリ検査
CGraphQL認可フィールド単位の認可、過剰なクエリ
Cプロトタイプ汚染JavaScriptオブジェクトの継承構造の悪用
CTOCTOU検査と利用の間に状態が変更される競合
CWAF / RASP攻撃検知・防御の仕組みと、業務認可不備への限界

2. 認証と認可を分けて考える

科目BのWeb問題で最も多い誤答は、認証(誰か)と認可(何をしてよいか)の混同 である。

  • 認証:ログインに成功した、セッションが有効である、JWTの署名が正しい
  • 認可:その利用者が このリソース に この操作 をしてよい

「ログイン済みであることは確認しているが、対象データの所有者かどうかは確認していない」というコードが、IDOR/BOLAの典型である。

2.1 IDOR / BOLA(オブジェクト単位の認可不備)

GET /api/orders/10235
Cookie: session=...(利用者Aのセッション)

サーバ側の処理が次のようになっていると、利用者Aは番号を変えるだけで他人の注文を閲覧できる。

# 欠落あり:ログインの確認のみ
order = db.query("SELECT * FROM orders WHERE id = ?", order_id)
return order
# 修正:所有者をサーバ側で照合する
order = db.query(
    "SELECT * FROM orders WHERE id = ? AND user_id = ?",
    order_id, session.user_id)
if order is None:
    return 404

答案の型:「注文IDに対応する注文の所有者がログイン中の利用者と一致するかを、サーバ側で検証していない。」

推測しにくいID(UUID)にするのは補助策であって、認可検証の代わりにはならない。設問で「根本的な対策」を問われたら、必ずサーバ側の認可検証を書く。

2.2 BFLA(機能単位の認可不備)と垂直権限昇格

管理画面のメニューを一般利用者に 表示しない だけで、API側で役割を検証していない状態。

POST /api/admin/users/123/role   {"role": "admin"}
  • 水平権限昇格:同じ権限レベルの他人のデータにアクセスする(IDORと同じ構造)
  • 垂直権限昇格:一般利用者が管理者の機能を実行する(BFLA)

対策は、すべてのAPIで、サーバ側で役割(ロール)を検証すること。画面の制御(ボタンを隠す)は対策にならない。

2.3 マスアサインメント

リクエストの属性をそのままモデルに代入すると、本来は利用者が変更できない属性まで書き換えられる。

PUT /api/users/me   {"name": "Alice", "is_admin": true}

対策は、更新を許可する属性を明示的に列挙すること(許可リスト方式)。


3. インジェクション系

インジェクションの共通構造は、データとして扱うべき入力が、命令(構文)の一部として解釈される ことである。対策も共通で、データと構文を分離する仕組みを使う。

種類解釈する処理系根本対策
SQLインジェクションDBプレースホルダー(バインド機構)
OSコマンドインジェクションシェルシェルを経由しないAPI、引数を配列で渡す
XSSブラウザー(HTML/JS)出力文脈に応じたエスケープ、CSP
XXEXMLパーサー外部実体・DTDの無効化
パストラバーサルファイルシステムファイル名を直接使わない、正規化後に基準ディレクトリ内か確認

3.1 SQLインジェクション

# 脆弱:文字列の連結で構文を組み立てている
sql = "SELECT * FROM users WHERE name = '" + name + "'"

# 修正:プレースホルダー
db.query("SELECT * FROM users WHERE name = ?", name)
  • エスケープ処理は補助策。根本対策を問われたらプレースホルダーを書く。
  • DBアカウントの権限を最小にすると、被害の範囲を限定できる(多層防御)。
  • エラーメッセージにSQL文やDB構造を表示しない。

3.2 XSS

種類スクリプトの混入位置実行経路
反射型リクエストのパラメータサーバがそのまま応答に埋め込む
格納型DBなどに保存されたデータ閲覧した全利用者のブラウザーで実行される
DOM型クライアント側JSの処理innerHTML などでブラウザーが組み立てる(サーバを経由しないこともある)

対策:

  • 出力する文脈(HTML本文、属性値、JavaScript、URL)に応じてエスケープする。
  • DOM型では innerHTML の代わりに textContent を使う。
  • CSPで、許可していないスクリプトの実行を防ぐ(多層防御)。
  • Cookieに HttpOnly を付けると、スクリプトからのCookie読み取りを防げる。ただし、XSSそのものを防ぐわけではない(利用者になりすました操作はできてしまう)。

3.3 OSコマンドインジェクション・パストラバーサル

  • OSコマンドインジェクションは、シェルのメタ文字(; | & など)が解釈されることが成立条件。シェルを起動しない関数を使い、引数を配列で渡すのが根本対策。
  • パストラバーサルは、ファイル名に ../ を含めて基準ディレクトリの外を参照させる。ファイル名を利用者に指定させず、IDとの対応表で管理するのが最も確実。

3.4 XXE

XMLの外部実体参照を使って、サーバ上のファイルや内部ネットワークのURLを参照させる。XMLパーサーの設定で、DTDと外部実体の処理を無効にする。


4. ブラウザーの仕組みと攻撃・防御

4.1 同一オリジンポリシー(SOP)とCORS

  • オリジン=スキーム+ホスト+ポート。
  • SOPは、別オリジンのレスポンスをJavaScriptで 読む ことを制限する。リクエストの 送信 そのものは防がない。これがCSRFが成立する理由である。
  • CORSは、サーバが応答ヘッダーで「このオリジンからの読み取りを許可する」と宣言する仕組み。SOPを 緩める ためのものであり、防御の仕組みではない。

設定ミスの典型:リクエストの Origin ヘッダーの値をそのまま Access-Control-Allow-Origin に返し、さらに Access-Control-Allow-Credentials: true を付けている。任意のサイトから、利用者の認証情報付きで応答を読まれる。

4.2 CSRF

成立条件:

  1. 利用者が対象サイトにログイン済み(Cookieが自動送信される)
  2. 状態を変更する処理が、推測可能なリクエストだけで実行できる
  3. サーバがリクエストの送信元を確認していない

対策:

  • 推測できないトークン(CSRFトークン)を埋め込み、サーバで照合する。
  • Cookieに SameSite=Lax または Strict を付ける。
  • 重要な操作では再認証を求める。

4.3 Cookie属性

属性効果付けない場合のリスク
SecureHTTPS通信でのみ送信平文のHTTP通信で盗聴される
HttpOnlyJavaScriptから読み取れないXSSでCookieを読み取られる
SameSite別サイトからのリクエストに付けるかを制御CSRF
Domain送信先のドメイン範囲広く指定するとサブドメインにも送信される
Path送信先のパス範囲分離の補助にすぎない(セキュリティ境界ではない)

Domain 属性は 指定しない 方が送信範囲が狭くなる(発行したホストのみ)。サブドメインで第三者のサービスを使っている場合の問題で問われやすい。

4.4 セッション管理

攻撃成立条件対策
セッション固定化ログイン前のセッションIDがログイン後も使われるログイン成功時にセッションIDを再生成する
セッションハイジャックセッションIDの漏えい(XSS、盗聴、ログやURLへの記録)HttpOnly、Secure、URLにIDを含めない
推測セッションIDが連番や時刻に基づく暗号論的擬似乱数で十分な長さのIDを生成する

有効期限(無操作時と絶対的な上限)と、ログアウト時のサーバ側での破棄も確認する。

4.5 CSP(Content Security Policy)

Content-Security-Policy: script-src 'nonce-r4nd0m' 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'
ディレクティブ役割
script-src実行を許可するスクリプトの取得元
nonce応答ごとに変わる値を持つ <script> だけを許可
hash内容のハッシュ値が一致するスクリプトだけを許可
frame-ancestors自ページを埋め込めるページ(クリックジャッキング対策)
report-uri / report-to違反を報告する送信先

CSPが効かなくなる条件(2025年度に関連する論点):

  • 'unsafe-inline' を許可している
  • nonceが固定値、または推測できる
  • 許可しているオリジンに、利用者が任意のファイルを置ける(CDNの共有領域、アップロード機能など)
  • 許可しているオリジンに、応答の内容を呼出し側が指定できるエンドポイント(JSONPなど)がある

CSPは 多層防御 であり、XSSの根本対策(出力エスケープ)の代わりにはならない。

4.6 クリックジャッキング

透明にした対象サイトを別ページに重ね、利用者に意図しないクリックをさせる。Content-Security-Policy: frame-ancestors または X-Frame-Options で埋め込みを制限する。


5. サーバ側から内部へ向かう攻撃

5.1 SSRF

利用者が指定したURLにサーバがアクセスする機能(画像の取込み、Webhook、URLのプレビュー)を使い、外部からは届かない宛先にサーバ自身からアクセスさせる。

狙われる宛先:

  • 社内API、管理画面(送信元がサーバなので、IPアドレス制限を通過してしまう)
  • クラウドのメタデータサービス(一時的な認証情報を取得できる場合がある)

対策:

  • 宛先を許可リストで制限する(拒否リストはリダイレクトやDNSの再解決で回避されやすい)。
  • 名前解決した 後の IPアドレスで判定し、プライベートアドレスやリンクローカルアドレスを拒否する。
  • メタデータサービスへのアクセスにトークンを必須にする方式(AWSのIMDSv2など)を使う。
  • サーバからの外向き通信をFWで制限する。

5.2 ファイルアップロード

  • 拡張子や Content-Type ヘッダーは偽装できる。ファイルの実体(中身)を検査する。
  • Webサーバの公開ディレクトリに保存しない。保存先ではスクリプトの実行を禁止する。
  • ファイル名はサーバ側で生成し直す。

5.3 HTTPリクエストスマグリング・キャッシュポイズニング

  • スマグリング:フロントのプロキシとバックエンドで、リクエストの区切り(Content-Length と Transfer-Encoding)の解釈が異なることを利用し、次のリクエストに別の内容を紛れ込ませる。
  • キャッシュポイズニング:キャッシュキーに含まれないヘッダーで応答の内容が変わる場合に、細工した応答をキャッシュさせ、他の利用者に配信させる。

いずれも、複数の機器の間で解釈が一致していない ことが成立条件になる。構成図にリバースプロキシやCDNが出てきたら疑う。


6. JWTとAPI

確認項目欠落した場合
署名の検証内容を改ざんしたトークンを受け入れる
alg の固定none や想定外のアルゴリズムへの差し替えを受け入れる
iss(発行者)別の発行者のトークンを受け入れる
aud(受信者)別のサービス向けのトークンを流用される
exp(有効期限)漏えいしたトークンを無期限に使われる
鍵の管理共通鍵が漏えいすると、誰でも正規のトークンを作成できる

JWTの中身(ペイロード)はBase64URLでエンコードされているだけで、暗号化されていない。機密情報を入れない。

APIレート制限:ログインの試行、IDの列挙、データの大量取得を防ぐ。利用者単位・IPアドレス単位・APIキー単位で制限し、超過した場合は 429 Too Many Requests を返す。


7. Webスキミング

決済画面に不正なスクリプトを埋め込み、入力されたカード情報を外部に送信させる攻撃。

侵入経路対策
サイトの改ざん(管理画面への不正ログイン、CMSの脆弱性)管理画面の接続元制限、MFA、改ざん検知
外部から読み込んでいるスクリプトの改ざんSRI(Subresource Integrity)、読込み元の削減
送信先の追加CSPの connect-src / form-action で送信先を制限

カード情報を自社で扱わない方式(決済代行会社の画面への遷移、トークン化)を選ぶことも、根本的な対策として問われる。


8. 開発プロセスとツール

手法対象特徴
脅威分析(脅威モデリング)設計STRIDEなどで、設計段階で脅威を洗い出す
SASTソースコード実行せずに解析する。開発の早い段階で使える
DAST動作中のアプリ外部から実際にリクエストを送る。設定不備も見つかる
SCA依存ライブラリ既知の脆弱性があるバージョンを検出する
WAF通信既知の攻撃パターンを遮断する。業務上の認可不備(IDORなど)は検知できない
RASP実行環境アプリの内部で攻撃を検知する

WAFの限界は頻出である。「正規の利用者が、正規の形式のリクエストで、他人のIDを指定する」攻撃は、パターンでは区別できない。


9. 補強(C)

  • GraphQL:1つのエンドポイントで多くのデータを取得できるため、フィールド単位の認可と、クエリの深さ・コストの制限が必要。
  • プロトタイプ汚染:JSONの __proto__ などのキーを通じて、全オブジェクトが継承する属性を書き換える。キーの許可リスト、継承を持たないオブジェクトの利用で防ぐ。
  • TOCTOU:残高の確認と引落としの間に別のリクエストが割り込むなど。DBのトランザクションや排他制御で防ぐ。

10. 読解のチェックリスト

ソースコードやリクエストを見たら、次の順で確認する。

  1. このAPIは 誰が 呼び出せるべきか(認証)
  2. どのデータ に対する操作か。所有者や所属組織を照合しているか(認可)
  3. 入力値は どの処理系 に渡るか(SQL、シェル、HTML、XML、ファイルパス、URL)
  4. 応答は どの文脈 に出力されるか
  5. ブラウザーが自動で送るもの(Cookie)に依存していないか
  6. サーバが 外部や内部へ 通信する機能はないか

~Yu Tokunaga