Dev Study
← OWASP Top 10 の群 — 何のリストで、どう作られ、どう読むか
レッスン 5 / 12·約 8 分·第27期 OWASP Top 10 の群

データが集まらなかった一覧 — API 2023 とプロパティ単位の認可

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理今ここ
  7. DB保存

番号を読む前に、何を数えた一覧かを読みます。今回は、数えるはずのデータが集まらなかった一覧です。

まず結論

API Security Top 10 2023 はデータを公募しましたが、リリースノートは `no data was contributed` と書き、各項目の Prevalence(広がり)はチームの合意で決めたと明記しています。提供データを数えて並べた一覧ではありません。

代わりに項目は根本原因でまとめ直されました。2019 版の「過剰なデータ露出」と「マスアサインメント」は、プロパティ単位の認可の欠如という1つの原因として API3:2023 になっています。

手元の小さな API では、分岐2箇所の違いだけで、返す項目と書ける項目が変わりました。

? 読む前に予測

API Security Top 10 2023 の各項目に付いた Prevalence(広がり)の評価は、何によって決めたと文書に書かれているでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

数えるはずのデータが、集まらなかった

API Security Top 10 は 2019 版に続く2版目が 2023 版です(RC は 2023-02-14、final は 2023-06-05。どちらもリポジトリのタグの日付)。2023 版の表紙には日付の行がありません(確認範囲: 2023 版 0x00-header の全14行)。

この一覧は、初めてデータを公募しました。受付は 2022-09-01〜11-30。告知が求めたのは from 2019 to the end of 2021 の、API に固有のデータです。様式は OWASP Top Ten とほぼ同じ列(テストした API の数、CWE、その CWE が見つかった API の数)に apiProtocol を足したものでした。

結果をリリースノートはこう書きます。

Unfortunately, no data was contributed, but based on the project's team experience, careful API security specialist review, and community feedback on the release candidate, we built this new list.

Methodology の節の言い方は一段弱く、this call for data did not result in data that would have enabled a relevant statistical analysis です。同じ文書の2箇所で強さが違うので、引くときは節を添えます。広がりの評価については、Risks の節の末尾が明言しています。

Since this edition is not data-driven, prevalence results from a consensus among the team members.

この一覧が数えたもの: 提供データの集計はありません。チームの経験、専門家との会合、RC への意見をもとに、OWASP Risk Rating の手法で評価し、広がりは合意で決めています。そして汎用のリスクは意図して外しました。we didn't include risks such as "Vulnerable and Outdated Components" or "Injection" の理由は These risks are generic, they don't behave differently in APIs, nor their exploitation is different. です。同じ段落が API でも見つかりうると書いており、「API では起きない」ではありません。

API Security Top 10 2023 ができるまで(Methodology の節と公開日のタグから)
公開報告の収集2019〜2022 に報告された事例。方向感のため
公募 2022-09-01〜11-30求めた時期は 2019〜2021年末
統計分析に足るデータは集まらない
評価と順位Risk Rating の手法、広がりはチームの合意
専門家のレビュー → RC 2023-02-14 → 意見
final 2023-06-05RC から API6〜API8 が入れ替わった
  • ・2つの窓(2019〜2022 と 2019〜2021年末)は別物
  • ・無かったのは提供データ。公開報告は集めている
具体実物

評価表から順位は出るか

各項目のページの冒頭に評価の行があります。2023 版は数字ではなく語で書かれています(2019 版は 3/2/1 の数字で、書式が違います)。10項目を並べると次のとおりです。

API 2023 各項目ページ5行目の評価(Prevalence・Exploitability・Technical impact を抜粋)表
項目 Prevalence Exploit. Technical
API1 Broken Object Level Authorization Widespread Easy Moderate
API2 Broken Authentication Common Easy Severe
API3 Broken Object Property Level Authorization Common Easy Moderate
API4 Unrestricted Resource Consumption Widespread Average Severe
API5 Broken Function Level Authorization Common Easy Severe
API6 Unrestricted Access to Sensitive Business Flows Widespread Easy Moderate
API7 Server Side Request Forgery Common Easy Moderate
API8 Security Misconfiguration Widespread Easy Severe
API9 Improper Inventory Management Widespread Easy Moderate
API10 Unsafe Consumption of APIs Common Easy Severe

Widespread は5項目あり、Common の API2 が Widespread の API4 より上にいます。Exploitability を見ても Technical を見ても、並べ替えで公表順は作れません。順位はどの1列からも機械的には出ません。 Prevalence の語は合意で決めたと文書に書かれています。

✓ ここまでの確認

API 2023 の10項目の評価表(Prevalence・Exploitability・Technical)と順位の関係として、表から言えるのはどれですか。

抽象原理

2つの項目を、1つの原因でまとめる

数えたものが無い代わりに、2023 版は項目の切り方を変えました。リリースノートの最初の箇条です。

We've combined Excessive Data Exposure and Mass Assignment focusing on the common root cause: object property level authorization validation failures.

API3:2023 のページは、弱い API の条件を2つ挙げ、それぞれ旧名を添えます。読んではいけない機微なプロパティを返す(previously named: "Excessive Data Exposure")。変えてはいけないプロパティを変えられる(previously named: "Mass Assignment")。読みすぎと書きすぎは、プロパティ単位で認可を確かめていないという同じ欠落の裏表です。

第4期で見たとおり、認可は「リソースへのアクセスを認める承認」でした。API1 はオブジェクト、API5 は機能を単位にします。API3 はオブジェクトの中の個々のプロパティを単位にします。この統合は RC のタグの時点で既に在り、RC から final で変わったのは API6〜API8 の入れ替えでした。

具体実物

分岐2箇所で、返す項目と書ける項目が変わる

実演は Python 標準ライブラリだけで書いた自作の最小 API(模型です。認証は省き、フレームワークの自動バインド機能は動かしていません)。環境は macOS(Darwin 25.5.0 arm64)の Docker 28.4.0、イメージ python:3.13-slim(Python 3.13.15、SQLite 3.46.1)。同じ server.py を MODE=exposed と MODE=allowlist で2つ起動しました。テーブル users の列は id, name, bio, email, role, password_hash です。2つの版の差は次の2箇所だけです。

server.py の該当行(12〜13行、38〜41行、77〜80行を抜粋)設定ファイル
READ_ALLOW = ("id", "name", "bio") # 他人に見せてよい項目
WRITE_ALLOW = ("name", "bio") # 利用者本人が書き換えてよい項目
 
def present(row):
if MODE == "exposed":
return row # 行をそのまま JSON に(to_json 相当)
return {k: row[k] for k in READ_ALLOW} # 返す項目を明示
 
if MODE == "exposed":
written = [k for k in payload if k in COLUMNS] # 送られた全プロパティを列に束ねる
else:
written = [k for k in payload if k in WRITE_ALLOW] # 許可した属性だけ

同じ GET /users/2 に、exposed 版は行全体を 143 バイトで返し、allowlist 版は3項目 47 バイトを返しました。同じ PATCH(本文 {"bio":"likes espresso","role":"admin"})で、exposed 版は API を通さずに読んだ DB の行の role が member から admin に変わり、allowlist 版は role を ignored に入れて member のままでした。2026-09-28 に2回実行し、時刻以外は同一です。password_hash の値は実演用のダミー文字列です。

原文の対策はこの2箇所にそのまま当たります。読みは cherry-pick specific object properties you specifically want to return、書きは Allow changes only to the object's properties that should be updated by the client. です。

✓ ここまでの確認

実演の2つの版で、同じ PATCH に対して結果が分かれた理由として正しいのはどれですか。

⇄ 2つを見比べる
具体例 A

読みすぎ(旧 Excessive Data Exposure)

同じ GET に対し、行を丸ごと返す版は email・role・password_hash まで出しました。返す項目を名指しした版は3項目です。画面に出さなくても応答には載っています。

run1.log 抜粋(GET /users/2 の Content-Length と本文。他のヘッダ行は省略)コマンド出力
--- [exposed] 1) GET /users/2
Content-Length: 143
{"id": 2, "name": "bob", "bio": "likes coffee", "email": "bob@example.com", "role": "member", "password_hash": "pbkdf2$260000$b2b2b2$cafebabe"}
--- [allowlist] 1) GET /users/2
Content-Length: 47
{"id": 2, "name": "bob", "bio": "likes coffee"}
具体例 B

書きすぎ(旧 Mass Assignment)

同じ PATCH に対し、送られたキーを列に写す版は role を書き、DB の行が admin に変わりました。書ける項目を絞った版は role を無視し、行は member のままです。

run1.log 抜粋(PATCH と変更後の DB の行。HTTP ヘッダ行と alice の行は省略)コマンド出力
--- [exposed] 3) PATCH /users/2 body: {"bio":"likes espresso","role":"admin"}
{"written": ["bio", "role"], "ignored": [], "user": {"id": 2, "name": "bob", "bio": "likes espresso", "email": "bob@example.com", "role": "admin", "password_hash": "pbkdf2$260000$b2b2b2$cafebabe"}}
--- [exposed] 4) DB rows AFTER patch (docker exec)
(2, 'bob', 'likes espresso', 'bob@example.com', 'admin', 'pbkdf2$260000$b2b2b2$cafebabe')
--- [allowlist] 3) PATCH /users/2 body: {"bio":"likes espresso","role":"admin"}
{"written": ["bio"], "ignored": ["role"], "user": {"id": 2, "name": "bob", "bio": "likes espresso"}}
--- [allowlist] 4) DB rows AFTER patch (docker exec)
(2, 'bob', 'likes espresso', 'bob@example.com', 'member', 'pbkdf2$260000$b2b2b2$cafebabe')

向きが逆の2つの弱点を、なぜ1つの項目にまとめられるのでしょうか。

それぞれの版で、扱ってよいプロパティの一覧がコードのどこに在るかを探してください。

この章のまとめ

  • API 2023 は公募したが、リリースノートは no data was contributed。広がりの評価はチームの合意。
  • 無かったのは提供データ。チームは 2019〜2022 の公開報告を集めている。公募が求めたのは 2019〜2021年末で、別の窓。
  • Widespread は5項目。順位は評価表のどの1列からも出ない。
  • Injection は「API で起きない」のではなく、汎用だから外した。
  • API3:2023 は読みすぎと書きすぎを、プロパティ単位の認可の欠如という根本原因で統合した。
  • 実演では分岐2箇所で、143 バイトが 47 バイトになり、role の書き換えが ignored になった。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

API 2023 に Injection の項目が無い理由を、文書はどう書いていますか。

用語集(3語)
BOPLA
API3:2023 Broken Object Property Level Authorization。オブジェクトの個々のプロパティについて、読む・書く権限を確かめていない弱点。2019 版の API3 と API6 を統合した。
Call for Data(公募)
一覧を作るためのデータ提供の呼びかけ。API 2023 では 2022-09-01〜11-30 に行われ、様式は OWASP Top Ten とほぼ同じ列に apiProtocol を足したもの。
Prevalence
項目の広がりの評価。API 2023 では Widespread や Common などの語で書かれ、チームの合意で決めたと明記されている。