コース目次 / 第2章
BOLA — リゾルバの、所有者チェック漏れ
noteフィールドに他人のIDを渡し、所有者チェックなしで非公開メモを読み出します。sec-authzのIDORとの対応を確認し、二アカウント法でGraphQLでも同じ手順が使えると理解します。
前章の vuln-api.js を、そのまま使います。BOLA(Broken Object Level Authorization)——GraphQL 業界での呼び名がついていますが、正体は sec-authz で見た IDOR と、まったく同じ形です。
攻撃 — 引数の ID を、他人のものに
note フィールドは、id を指定すると、そのメモを返します。太郎(X-UID: 1)のまま、花子のメモ(id: 102)を指定します。
curl -s -X POST -H "Content-Type: application/json" -H "X-UID: 1" \
-d '{"query":"{ note(id: 102) { id owner text } }"}' \
http://127.0.0.1:4200/
{"data":{"note":{"id":102,"owner":2,"text":"花子の非公開メモ"}}}
太郎のまま、花子の非公開メモが読めてしまいました。原因は、リゾルバのこの1行——
note: ({ id }) => notes[id]
「呼び出した uid(太郎)が、この note の owner か」を、一度も確認していません。旗艦コース(sec-web-basics)の /notes/:id、sec-authz の /orders/:id と、寸分違わず同じ穴です。URL が GraphQL の引数に変わっただけです。
二アカウント法は、そのまま使える
sec-authz で学んだ二アカウント法——「自分の資源のIDを控え、他人のIDを自分のセッションで試す」——は、GraphQL でもまったく同じ手順で使えます。
1. 太郎(X-UID: 1)でログインし、me や一覧クエリで自分の資源のIDを控える。
2. 花子(X-UID: 2)側の資源IDを、何らかの経路で知る(introspection や、連番の推測)。
3. 太郎のセッション(X-UID: 1)のまま、花子のIDを引数に渡して問い合わせる。
4. 返ってきたら、BOLA。
GraphQL の見た目(クエリ文)がREST(URL)と違っても、「同じ立場の他人の資源に、IDを変えるだけで手が届くか」を試すという発想は変わりません。
診断でGraphQLを見るときの、着眼点
GraphQL のスキーマは、Int や ID 型の引数を取るフィールドを、一覧で示してくれます(前章の introspection)。診断では、「IDを引数に取るフィールドを、まず全部リストアップする」ところから始めます。それぞれについて、「他人のIDを渡したら、何が返るか」を機械的に試す——これが GraphQL 版の BOLA チェックリストです。
持ち帰る一言
BOLAは、GraphQL 版のIDOR。 リゾルバが「この資源は呼び出した人のものか」を確認していないことが原因で、直し方も同じ——資源を返す直前に、所有者を確認する。次は、もう一つの認可の穴(BFLA)と、GraphQL特有の穴(mass assignment)を見ます。
こうなっていればOK
卒業まであと3章です。
この章はまだ完了していません。
保存できませんでした(プライベートブラウズ中かもしれません)。この端末に進捗は残りませんが、先へは進めます。