コース目次 / 第2章

ルールを締める — 認証と所有者を要求する

認証情報と所有者一致を要求するルールに直し、同じ攻撃が拒否されることを再検証します。本物のFirestoreルール構文との対応と、既定拒否の原則を確認します。

第2章 / 全4章目安 約9分この章のゴール: 認証と所有者を要求するルールに直し、再検証できるようになる

前章のモックを、OPEN=1 を外して起動するだけで、実は直っています——コード自体には、すでに認可チェックが書いてありました。それを、あらためて読み解きます。

直っているコード

if (!OPEN) {
  const uid = auth ? auth.replace('Bearer ', '') : null;
  if (uid !== doc.owner) { res.writeHead(403); res.end(JSON.stringify({ error: 'PERMISSION_DENIED' })); return; }
}

1. 認証情報(Authorization ヘッダー)が無ければ、uid は null——doc.owner(“u1” や “u2”)と一致するはずがないので、拒否されます。
2. 認証情報があっても、それが「そのドキュメントの持ち主」でなければ、やはり拒否されます。
これは、Firestore の実際のルール構文で書けば、こういう形に相当します。

match /users/{userId} {
  allow read, write: if request.auth != null && request.auth.uid == userId;
}

request.auth != null(ログインしているか)と、request.auth.uid == userId(本人か)。モックのコードでやっていたことと、まったく同じ2段の確認です。

再検証

node mock-firestore.js   # OPEN を付けない = 締まったルール
# 認証なし
curl -s "http://127.0.0.1:4300/v1/projects/demo-app/databases(default)/documents/users/u2"
# => {"error":"PERMISSION_DENIED"}

# 他人(太郎)として、花子のドキュメントを読む
curl -s -H "Authorization: Bearer u1" \
  "http://127.0.0.1:4300/v1/projects/demo-app/databases(default)/documents/users/u2"
# => {"error":"PERMISSION_DENIED"}

# 本人(花子)として
curl -s -H "Authorization: Bearer u2" \
  "http://127.0.0.1:4300/v1/projects/demo-app/databases(default)/documents/users/u2"
# => {"owner":"u2","name":"架空花子", ...}(正しく読める)

認証なし・他人としてのアクセスは拒否され、本人としてのアクセスだけが通ります。sec-authz の「水平の権限昇格」への直しと、寸分違わぬ形です——資源を返す直前に、認証済みか・本人かを確認する。BaaS の世界でも、認可の原則は変わりません。

既定は拒否 — ルールにも、同じ発想

実際の Firestore・Firebase Storage は、ルールを何も書かなければ、既定ですべて拒否する設計です(allow read, write: if false; 相当)。sec-securecoding の「既定は拒否、例外は理由付きで最小に」が、ルールエンジンの設計そのものに現れています。
実際のプロジェクトを持っているなら、Firebase CLI のエミュレータ(firebase emulators:start)を使うと、本物のルールに対して、このコースでやったのと同じような確認を、安全な模擬環境で行えます。

持ち帰る一言

ルールは、認証と所有者の2段で締める。 「ログインしているか」と「本人か」——この2つを、資源へのアクセスを許す条件式として明示する。サーバコードが無くても、認可の原則(事実は正しい場所で確認する)は変わりません。次はまとめて、このコースを締めます。

こうなっていればOK

卒業まであと1章です。

この章はまだ完了していません。