APIセキュリティとは?認証と認可の違い・守り方を図解
ログインできたのに、別の人の注文まで見えてしまう。
そんなAPIは、ログイン機能が正常に動いていても安全とはいえません。
APIセキュリティでは、誰が呼んだかに加え、その人がどのデータに何をしてよいかを、サーバー側で確かめます。
この記事では、架空の注文APIを例に、設計とテストでどこを見ればよいかを図で整理します。
この記事は以下のような人におすすめ!
- APIを初めて設計・レビューする人
- 認証と認可の違いを具体例で知りたい人
- 公開前に使える確認項目を探している人
APIの入口では「誰が」「何をするか」を分けて見る
1-1. アプリの画面を飛ばしても、同じ制約が必要
注文履歴を開くと、画面の裏ではアプリがAPIに問い合わせ、サーバーが注文を返します。
画面は使いやすい入口ですが、どの注文を返してよいかを最終判断するのはサーバーです。
例えば、一覧画面に自分の注文だけを表示していても、詳細APIが別の注文を返すなら保護はできていません。
ボタンを隠す工夫は操作ミスを減らしますが、アクセス制御の代わりにはなりません。

1-2. 認証、認可、暗号化が答える質問
認証は「呼び出しているのは誰か」、認可は「その人がその操作をしてよいか」を確かめる処理です。
認証で会員Aと分かっても、会員Bの注文を読んでよいことにはなりません。
HTTPSは、通信の途中でデータを読まれたり書き換えられたりしにくくするために使います。
通信を暗号化しても、サーバーが誤って別人の注文を返す問題は残ります。
守る場所がそれぞれ違う、と覚えると混乱しません。
(参考1)
ログイン済みでも、他人の注文は見せない
2-1. 注文番号は権限の証明にならない
会員Aには A-104、会員Bには B-205 という注文があるとします。
注文詳細のAPIが「指定された番号の注文を探す」だけなら、AからBの注文番号が届いたときも返してしまいます。
サーバーは、認証済みの主体と、対象の注文との関係を確認します。
本人、同じ組織内の担当者、サポート担当など、どの関係で参照が許されるかはサービスごとに決めます。
端末から送られてきた所有者の申告をそのまま信用すると、判断の根拠が利用者の入力に戻ってしまいます。

2-2. IDの変更を想定した設計にする
こうした問題は、OWASPのAPI Security Top 10 2023で、オブジェクト単位の認可の不備、BOLAと呼ばれています。
ここでいうオブジェクトは、注文やファイルのように、APIがIDで指定して扱う一つのデータです。
注文番号を推測しにくくすると偶然の発見は減らせますが、別の経路で番号を知った場合にも拒否できる必要があります。
詳細だけでなく、更新、削除、一覧、ダウンロードも、操作ごとに許可条件を揃えてください。
例えば、サポート担当が参照できることと、配送先を変更できることは別です。
(参考2)
トークン・入力・返却データを守る
3-1. 有効なトークンでも、できる操作には範囲がある
アクセストークンは、APIへアクセスするときに使う資格情報です。
発行元や有効期限など、その方式で検査すべき条件を確認します。
JWTを使う設計なら、読み取れたというだけで信用せず、署名や対象サービスも設定したルールで検証します。
注文を「読む」権限を持つトークンを受け付けた後も、その人が指定された注文を読めるかは別に判定します。
OAuthの仕組みを取り入れたことだけで、この対象単位の判断が自動で備わるわけではありません。
(参考1)

3-2. 画面に見えない項目も、返せば届いている
例えば、注文一覧に注文日と配送状況しか出さないなら、APIが内部メモまで返す理由はありません。
画面に表示されなくても、応答を受け取る側にはデータが届いています。
反対に、変更時は「受け取ってよい項目」を限定します。
配送希望日を変えるAPIで、金額や承認状態を一緒に受け取ってそのまま保存しないようにします。
読み取りと書き込みを、項目の単位でも分けて考えるのがポイントです。
(参考3)
公開前に、許可と拒否をセットで確認する
4-1. 二人分のダミーデータで期待結果を決める
自分の注文が見えることだけをテストすると、他の人の注文も見える実装を見落とします。
許可を受けた検証環境で会員AとBのダミーデータを用意し、正しい要求と、拒否されるべき要求を対にします。
例えば下の表のように、呼び出す主体、対象、操作を固定します。
失敗したときはステータスだけでなく、応答本文に注文情報が含まれていないか、更新処理なら保存された値に変化がないかも確認します。
| 主体 | 対象と操作 | 確認したい結果 |
|---|---|---|
| 会員A | 自分の注文 A-104 の参照 | 必要な項目だけ返る |
| 会員A | 会員Bの注文 B-205 の参照 | 注文の内容を返さない |
| 会員A | 参照のみ許可された注文の変更 | 変更を拒否し、保存値も不変 |
| 認証情報なし | A-104 の参照 | 認証を要求し、注文の内容を返さない |

4-2. 拒否理由の手がかりを残す
HTTPの401は、対象への有効な認証資格情報がないことを示します。
403は、要求を理解したうえで実行を拒否する応答です。
存在を隠したい対象について404を返せる場合もあります。
サービスの方針を決め、拒否した画面に内部情報を出しすぎないようにします。
(参考4)
ログでは、追跡用のリクエストID、時刻、操作、結果などを残すと、問い合わせに対応しやすくなります。
一方で、トークンや注文の詳細を丸ごと残すと、ログから漏れる範囲が広がります。
何があれば調べられるかを決めてから、記録する項目を絞りましょう。
4-3. 一度に取得できる量も決めておく
本人の注文でも、1回で大量のデータを返す要求を許すと、処理能力を圧迫する場合があります。
1ページの件数、要求の頻度、重い操作の扱いを、正常な利用の範囲と照らして決めます。
頻度制限の応答を受けたクライアントは、即座に繰り返すと負荷を増やします。
例えばMicrosoft Graphは429を返すときの待機方法を公開しています。
これは製品の例なので、自分が使うAPIでも同じ挙動と決めつけず、提供元の説明を確認してください。
(参考5)
確認やテストは、許可された検証環境とダミーデータで行います。
よくある質問
5-1. APIキーを付ければ利用者の認可も済みますか?
APIキーは、アプリやプロジェクトの識別や利用制限に使われることがあります。
利用者のIDや対象データの権限を表すかはサービスの方式次第です。
キーが有効かどうかだけで、別の利用者の注文を読めると判断しないでください。
5-2. 自分の組織内だけなら認可は省けますか?
社内でも部署や担当によって見てよい情報が違います。
例えば経理と配送担当が同じ注文を参照しても、見せる項目が同じとは限りません。
ネットワークの内側であることは、個別データの許可とは分けて扱います。
5-3. UUIDに変えればBOLAは防げますか?
UUIDのような推測しにくいIDは役立つ場合がありますが、IDが知られたときに拒否できる仕組みが必要です。
注文番号の種類を変えるより先に、対象への権限を判断する処理を確認します。

まとめ:1つのAPIで、許可と拒否を言葉にする
最初からすべてのAPIを点検するのは大変です。
まずは個人情報や支払い情報を扱うAPIを一つ選び、誰が、どの対象に、何をしてよいかを書き出してみてください。
会員Aが自分の注文を読めること、Bの注文は読めないこと。
その二つを検証環境で同時に確認できれば、仕組みを点検する足場になります。
設計レビューでも「ログインは付いていますか」から一歩進めて、「このIDの注文に対する許可はどこで確認しますか」と聞けます。

参考資料
- 参考1:OWASP — HTTPS、APIごとのアクセス制御、JWTの検証と入力の扱い
- 参考2:OWASP — 2023 API1、対象単位での認可と推測しにくいIDの限界
- 参考3:OWASP — 2023 API3、項目単位の認可、過剰な返却や更新
- 参考4:IETF — RFC 9110 §15.5、401・403・404の意味
- 参考5:Microsoft — Graphの429と待機方法。一般のAPIと区別。

