学習・技術検証用デモ — 本システムは実際の銀行サービスではありません。

公開情報をもとに構築した教育目的のシステムです。実在する個人情報・口座情報・機密情報・認証情報等を入力しないでください。

ミニ銀行ACADEMY SYSTEM LEARNING
教材メニュー
学習進捗0 / 134
あと134項目
INTERMEDIATE · 中級COURSE 04 · SOFTWARE ENGINEERING

APIとDBの責任境界

UIを信用せず、それでも使いやすいAPIを作るには、入力検証・認証・認可・業務不変条件・error公開をどこで担当するか決める必要があります。

05 / 11
SOFTWARE ENGINEERING · ソフトウェア工学

境界、transaction、並行制御、脅威、テスト、障害対応をFailure Firstで学ぶ。

先に学ぶ内容 — Prerequisite: 基礎 / 銀行システム

学ぶこと — LEARNING GOALS

このページで学ぶこと

  • UI・API・DBの責任分担
  • 認証と認可の実行位置
  • 安全なerror contract

体験30 · API / DB BOUNDARIES(責任を重ねる)

画面のボタンを無効化しておけば、APIへの不正な直接呼び出しも防げるか確かめよう

まずは予想をひと言。本文を読んだ後、教材内の参照元で実際のAPIとエラー変換を確認します。

体験学習 · STEP 1 / 5
  1. 01
    まず予想する — PREDICT

    まずここだけ:思ったことをひと言書く

    画面のボタンを無効化(disabled)しておけば、そのAPIへの不正な直接呼び出しも防げると思いますか?

    正解でなくて大丈夫です。「〜だと思う」から始めてみましょう。

    ヒント1を見る

    UIの制御と、サーバー側の確認は同じ場所で行われているでしょうか?

    ヒント2を見る

    APIを直接呼び出すツールがあったら、画面の制限は意味を持つでしょうか?

    もっと詳しく:この問いで使う専門用語
    • Trust boundaryは、入力やidentityをそのまま信用できなくなる境目です。
    • Defense in depthは、独立した複数の防御を重ねる考え方です。
    • Error contractは、callerが安定して扱えるerror codeと意味の約束です。
まずはひと言だけで大丈夫です。

この後の本文を最後まで読んでから、実際に操作して確かめるステップへ進みます。

日常語で理解する — PLAIN LANGUAGE

まず、ここだけつかむ

1

UIの非表示やdisabledは操作支援であり、認可ではありません。

2

APIは公開contract、DBはどの呼出経路でも破れないownership・状態・金額不変条件を担当します。

3

内部診断、安定error code、利用者messageを分離します。

順番に理解する — DIFFICULT PARTS, STEP BY STEP

難しいポイントを、順番にほどく

専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。

01

Trust boundary

やさしく言うと

入力やidentityをそのまま信用できなくなる境目です。

なぜ必要?

境界を跨ぐたびに検証責任を明確にします。

Minibankでは

browser→API→PostgREST→SECURITY DEFINERで再確認します。

02

Defense in depth

やさしく言うと

独立した複数の防御を重ねる考え方です。

なぜ必要?

1層の実装漏れが直ちに資金事故にならないようにします。

Minibankでは

validation、Auth、RLS、RPC認可、constraint、auditを重ねます。

03

Error contract

やさしく言うと

callerが安定して扱えるerror codeと意味の約束です。

なぜ必要?

DB messageは変化しやすく内部情報も含むためです。

Minibankでは

SQLSTATEを安全なAPI errorへmappingします。

発展 — ADVANCEDもっと詳しく確認する最初の学習では読まなくても問題ありません。仕組みをもっと深く理解したい場合に開いてください。

同じ検査を重ねる理由

層主な責任任せてはいけないこと
UI入力支援、確認、二重click抑止最終的な認可・金額整合性
APItoken検証、schema検証、公開contract、rate制御client申告のownerやadmin roleを信用すること
Serviceuse caseの組立て、error mappingDB transactionを複数callへ分断すること
DB RPCcaller再確認、状態・lock・不変条件・atomic write画面が正しく呼ぶという前提
Constraint / privilegeどの経路でも破れない最後の防御業務上の説明や利用者向けmessage

認証情報の流れ

  1. 01browserがaccess tokenを送る
  2. 02serverが署名済みtokenから利用者を確認
  3. 03APIがclient入力のuser idを捨てる
  4. 04DBがauth.uid()からcallerを再解決
  5. 05RLSまたはRPCが対象ownershipとroleを確認
  6. 06許可されたrecordだけを返す

errorを3層へ分ける

層例公開範囲
内部診断constraint名、SQL message、stack、request context権限を限定したlogのみ
安定codeINSUFFICIENT_FUNDS、INVALID_STATEAPI contractとprogram分岐
利用者message残高が不足しています画面。安全で行動可能な表現

設計演習:API直呼びを想定する

  • 別人のbank_account_idへ振込requestを送る
  • admin画面を経由せずfreeze RPCを呼ぶ
  • 同じidempotency keyで金額を変える
  • enum外の状態・負数・巨大値・余分なfieldを送る
  • 内部errorを意図的に起こしresponseを確認する

実際のMinibankでは

Next.js routeはAuth clientからuserを確認し、serviceを通じて公開RPCを呼びます。SECURITY DEFINER RPCは強権限だからこそ、`auth.uid()`、owner、role、status、固定search_path、EXECUTE権限を関数ごとに読みます。

PostgreSQLの生messageはclient contractにせず、安定codeを`mapRpcError()`で安全な日本語へ変換します。

体験学習の続き · LEARNING LOOP

ここまで読めましたか?続けて確認してみましょう

Trust boundaryとDefense in depthの考え方を読んだところで、教材内の参照元で実際のAPIとエラー変換を確認し、自分の言葉で説明してみます。

STEP 2〜5 / 5
  1. 02
    仕組みを確かめる — CONCEPT CHECK

    画面操作なしで、仕組みを確かめる

    この仕組みは、Mini Bankの画面には現れません。次のEvidenceとCode Trail、教材本文だけで理解を進めます。

  2. 03
    証拠を確認する — EVIDENCE

    何を見たか、1つずつ確かめる

    Evidence(判断の根拠となる記録)を確認したらチェックします。各項目の「何を見るか」を手がかりにしてください。

    画面を開けない項目は、Source Trail(教材の参照元)と教材の説明で確認できます。失敗を実際に起こす必要はありません。

  3. 04
    コードの処理経路を追う — CODE TRAIL

    コードを書く必要はありません

    ここでは「説明されている仕組みが、実際のMini Bankのどこに実装されているか」を確認します。まずは日本語の役割説明を読み、入力した依頼がどこへ渡るかをつかみましょう。コードの全文を読む必要はありません。

    まずHTTP境界がcallerをどう再確認するかを見て、次にDBエラーがどう安全な形式へ変換されるかを見ます。

    HTTP境界とrequest validation。callerの再解決をどこで行うかを探します。

    src/app/api/v1/

    DB errorから公開errorへの変換。

    src/lib/errors/rpcErrors.ts
    教材の参照元を確認する — Source Trail ↓
  4. 05
    自分の言葉で説明する — EXPLAIN

    LEVEL 1 — やさしい説明(まずここだけ)

    なぜUIで操作を制限するだけでなく、API・DBのそれぞれでも同じ確認を繰り返す必要があるのでしょうか? 短い2文を目安に説明してください。

    日常語だけで完了できます。専門用語の数や正誤を自動採点するものではありません。

    ヒント1を見る

    「Trust boundary」と「Defense in depth」という2つの言葉を使って書いてみましょう。

    ヒント2を見る

    UI・API・DBのどこが最後の防御かを考えてみましょう。

    もっと詳しく:LEVEL 2 — 専門用語を使った説明(任意)

    Trust boundary、Defense in depth、Error contractの3つを使って、UI・API・DBの責任分担を説明してみましょう。

    挑戦する場合は、上の説明欄に追記できます。追加しなくても完了できます。

    説明の確認ポイント — Checkpoint
    • UIの制限とサーバー側の認可は別だと説明できる
    • 内部診断情報と利用者向けメッセージが分離されていると説明できる
予想5文字以上・証拠2項目・説明20文字以上で完了できます。

証拠の確認:0 / 2。LEVEL 2(専門用語での説明)は任意です。

入力はこのブラウザに保存されます。Academy教材の進捗とは別の学習メモです。

理解を確かめる — CHECK YOUR UNDERSTANDING

3問で理解チェック

答えを頭の中で考えてから、各項目を開いて確認してください。

Q1APIがowner確認すればDBでは不要ですか?
答え

不要ではありません。別APIやRPC直呼び、将来のfilter漏れに備えDB境界でも確認します。

Q2service_roleで全tableを読み、APIで絞るのは安全ですか?
答え

通常利用経路では危険です。filter漏れが全件漏洩になるため、最小権限とDB側の範囲制御を使います。

Q3DBのmessage_textをそのまま返せますか?
答え

返しません。内部詳細を分離し、安定codeを安全な利用者messageへ変換します。

ここまで読めましたか?

完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。

教材の参照元 — SOURCE TRAIL

根拠と関連教材

CURRENT IMPLEMENTATIONは確認したrepository内の実装です。HISTORICAL IMPLEMENTATIONは導入・修正の履歴で、後続migrationによる再定義があり得ます。RELATED LESSONは教材への案内で、実装の一次Sourceではありません。ASSUMPTIONは仮定、UNKNOWNは未確認を表します。

確認基点: d02eae8914f39cbf06bfe422dc39c71886f82b3e / 2026-09-11。稼働環境への適用確認: UNKNOWN。パス実在の自動検査と、記述した技術的事実の確認は別です。

  • 現在の実装 — CURRENT IMPLEMENTATIONsrc/app/api/v1/HTTP境界とrequest validation
  • 現在の実装 — CURRENT IMPLEMENTATIONsrc/lib/errors/rpcErrors.tsDB errorから公開errorへの変換
  • 過去の実装 — HISTORICAL IMPLEMENTATIONsupabase/migrations/RLS・GRANT・SECURITY DEFINER RPC