トップ›基礎編›第2章
基礎編第2章

Webアプリの仕組みの最低限

読む目安:約40分ブラウザ・サーバー・DB・外部サービス。1回の操作で何が起きるか

「脆弱性がある」と言われても、アプリの中で何がどこで起きているかを知らなければ、想像のしようがありません。この章では、Webアプリの登場人物を4つに絞り、ボタンを1回押したときに何が起きるかを順番に追います。覚えることは多くありません。ただし、ひとつだけ「最重要の事実」があります。

この章の学習目標

  • ブラウザ、サーバー、データベース、外部サービスの4つの役割を、経理の言葉で説明できるようになる
  • ボタンを押してから画面が変わるまでに、リクエストとレスポンスがどう流れるかを図で説明できるようになる
  • 「ブラウザ側は利用者が自由に書き換えられる。だから検証はサーバー側で行う」という原則を、理由とともに説明できるようになる

4つの登場人物

Webアプリは、どれほど複雑に見えても、登場人物は4つに整理できます。経理部の窓口業務に置き換えると、役割がはっきりします。

登場人物役割経理でいえばあなたの環境では
ブラウザ画面を表示し、利用者の操作を受け付ける窓口。申請書を受け取る場所利用者のChromeやSafari
サーバー依頼を受けて処理する。検証と権限の確認もここ担当者。申請書を証憑と照合し、処理する人Vercel上で動くNext.jsの処理
データベースデータを保存し、読み書きに応じる金庫、または総勘定元帳Supabaseのテーブル
外部サービス自分の外にあって、呼び出して使う銀行や取引先Supabase Auth(ログイン)、メール送信、決済、AIのAPI

大切なのは、この4つが「別の場所」にあるということです。ブラウザは利用者のパソコンの中、サーバーとデータベースはあなたが契約したクラウドの中、外部サービスは他社の中にあります。場所が違えば、信用の度合いも違います。これが、このあとの話の土台になります。

1回の操作で何が起きるか

あなたの学習用ミニ銀行アプリで、利用者が「残高を見る」ボタンを押したとします。画面に残高が出るまでに、次のことが起きています。

ブラウザ 「残高を見る」を押す ① リクエスト 「口座105の残高をください」+ログインの証明 ④ レスポンス 「残高は 12,000円です」または「拒否」 サーバー ② 本人か・持ち主かを確認 してから、読みに行く ③ 読み書き データベース 口座・取引のテーブル 利用者の手元 あなたが管理する領域 信頼境界:ここから先は信用しない
図2-1 「残高を見る」を1回押したときの流れ。②の確認を飛ばしてデータベースを読みに行くと、第1章で1位だった「アクセス制御の不備」になります。
  1. リクエスト。ブラウザがサーバーに「口座105の残高をください」という依頼を送ります。このとき、ログイン済みであることの証明(後述のトークン)を一緒に添えます。
  2. 確認。サーバーは、添えられた証明が本物か、そして口座105がその利用者のものかを確かめます。
  3. 読み書き。確認が通ったら、データベースから残高を読みます。振込なら、ここで残高を書き換えます。
  4. レスポンス。結果をブラウザに返し、ブラウザが画面に表示します。

経理の窓口で言えば、申請者が窓口に申請書を出し(リクエスト)、担当者が申請者の身分と権限を確かめ(確認)、元帳を参照または記帳し(読み書き)、控えを渡す(レスポンス)という一連の流れです。MDN Web Docsの「ウェブのしくみ」では、この依頼と応答のやりとりがHTTPという約束事に沿って行われることが説明されています。

ログインの仕組み:証明を添えて依頼する

①で「ログインの証明を添える」と書きました。「本人かどうか」を毎回IDとパスワードで確かめていたら、操作のたびに入力が必要になります。そこでWebアプリは、次のようにしています。

  1. 最初に、IDとパスワード(または外部サービスのログイン)で本人確認をします。
  2. 確認が通ったら、サーバーが「ログイン済みの証明」を発行します。これがセッションまたはトークンです。
  3. 以後の操作では、ブラウザがその証明を毎回リクエストに添えます。サーバーは証明を見て、誰からの依頼かを判断します。

社員証に似ています。入館時に一度だけ身分を確かめ、以後は社員証を提示すれば通れる。便利な反面、社員証を落とせば拾った人が通れてしまいます。トークンも同じで、漏れれば他人がその人として操作できます。だからトークンはブラウザの中で丁寧に扱われ、一定時間で期限が切れるように作ります。OWASPのSession Management Cheat Sheetが、この扱い方の基準を示しています。

ここで、認証と認可を分けておきます。IDとパスワードで「あなたは誰か」を確かめるのが認証、確かめたうえで「あなたに何が許されているか」を決めるのが認可です。社員証を持っていることと、他部署の伝票を承認してよいことは別です。図2-1の②は、この両方を見ています。

最重要の事実:ブラウザ側は、利用者が自由に書き換えられる

この章でひとつだけ覚えるなら、これです。ブラウザで動いている画面は、利用者のパソコンの中にあります。ブラウザには「開発者ツール」という標準機能があり、表示されている文字も、ボタンの有効・無効も、サーバーに送る内容も、利用者が書き換えられます。これは不正でも裏技でもなく、ブラウザがそういう道具だということです。

ですから、「ブラウザ側で残高不足をチェックしているから、残高以上の振込はできない」は、守りになりません。チェックを外してボタンを押すのは利用者側の自由です。「管理者以外にはメニューを表示していない」も同じで、表示していないだけなら、URLを直接打てば届きます。

窓口に出された申請書に「残高確認済み」「承認済み」と書いてあっても、担当者はそれを信じません。申請者が自分で書けるからです。確認は担当者が自分で行い、担当者の記録だけを正とします。ブラウザは申請者、サーバーは担当者です。検証はサーバー側で行うという原則は、この意味です。ブラウザ側のチェックは、利用者が入力を間違えないための親切であって、統制ではありません。

補足:AIは、ブラウザ側だけで済ませたがる 第4章で詳しく見ますが、AIが作ったアプリでは「ブラウザ側で権限を判定して、サーバー側では判定していない」という作りが珍しくありません。画面上は正しく動くので、作った本人にも気づきにくいのです。確認する方法は第10章で扱います。

静的サイトと動的アプリ

あなたが公開しているものは、仕組みの面で2つに分かれます。

静的サイト動的アプリ
例Vercelに置いた教材サイト、用語集Supabaseを使う、ログイン付きのミニ銀行
サーバーの仕事用意済みのHTMLをそのまま返すだけ依頼ごとに処理を行い、データベースを読み書きする
利用者ごとの違いない。誰が見ても同じ画面ある。ログインした人ごとに違う内容
秘密情報原則として持たないデータベースの鍵、外部サービスのAPIキーを持つ
第1章の論文の対象含まれない含まれる

静的サイトは、図2-1でいうと②③がなく、①と④だけで完結します。預かるデータがないので、守るべきものはサイトそのものと、Vercelやレンタルサーバーのアカウントです。一方、動的アプリは②③があり、そこに利用者のデータと秘密情報があります。第1章の論文が調べたのは、この動的アプリの側です。どちらを作っているかで、必要な守りの深さが変わります。この切り分けを第3章で行います。

用語の整理

リクエスト
ブラウザがサーバーに送る依頼。「このページをください」「この口座の残高をください」「この内容で振込をしてください」。
レスポンス
サーバーがブラウザに返す応答。成功、拒否、見つからない、といった結果と、表示する内容。
API
Application Programming Interface。プログラム同士が依頼をやりとりするための窓口と手順。自分のサーバーが用意する窓口も、外部サービスが用意する窓口も、どちらもAPIと呼びます。
セッション
ログインしてからログアウトするまでの「状態」。サーバーが覚えていて、ブラウザは番号札(セッションID)で紐づきます。
トークン
ログイン済みであることの証明として発行される文字列。持っている人が本人として扱われるため、漏れるとなりすましになります。
環境変数
コードの外に置く設定値。データベースの接続情報やAPIキーのような秘密情報はここに置きます。Vercelでは設定画面から登録します。
フロントエンド/バックエンド
ブラウザ側で動く部分がフロントエンド、サーバー側で動く部分がバックエンド。信用できるのはバックエンドだけ、というのがこの章の結論です。

まとめ

  • Webアプリの登場人物は、ブラウザ(窓口)、サーバー(担当者)、データベース(金庫)、外部サービス(取引先)の4つ。それぞれ別の場所にあり、信用の度合いが違う。
  • 1回の操作は、リクエスト→サーバーでの確認→データベースの読み書き→レスポンスの順に進む。「確認」を飛ばすと、他人のデータに届く。
  • ブラウザ側は利用者が自由に書き換えられる。検証と権限の確認はサーバー側で行う。ブラウザ側のチェックは親切であって統制ではない。

出典