第11章:再生攻撃(リプレイ)対策:トークン使い回しを防ぐ♻️🚫
この章はひとことで言うと、**「同じApp Checkトークンを“何回も使い回して”叩かれるのを止める」**ための章です🧿✨ 特に AI機能(=お金が燃えやすい🔥) や 管理者操作(=事故ったら終わる😇) に効きます。
0) まず「リプレイ」って何?😈📼

App Check を入れて enforcement(強制) までONにすると、雑に curl で叩く“未検証リクエスト”は落ちます👍
でも…もし攻撃者が何らかの方法で 「正規ユーザーのトークン(App Checkトークン)」を1回ぶん入手できたら?
- そのトークンを 期限が切れるまで使い回して
- 同じAPIを 連打/自動化 して
- 画像生成・要約・変換みたいな 高コストAPIを“財布攻撃” できちゃう可能性があります💸💥
そこで出てくるのが Replay protection(β) です🛡️ これは 「トークンを“1回使ったら無効化(consume)”する」 仕組みです。(Firebase)
1) Replay protection(β)の全体像🧠🧩

Replay protection は、やることが2つだけです👇
A. サーバ側(Functions側)で「消費(consume)する」♻️✅
Callable Functions なら、関数定義に consumeAppCheckToken: true を付けるだけです。(Firebase)
- これで 検証後にトークンが消費され、同じトークンの再利用ができなくなるイメージです。(Firebase)
B. クライアント側(React側)で「使い捨てトークンを取る」🧾✨
Callable を呼ぶときに、limitedUseAppCheckTokens: true を付けます。(Firebase)
(カスタムバックエンドへ fetch する場合は getLimitedUseToken() を使います。(Firebase))
2) 超重要な注意⚠️(この章でハマりがちなところ)
✅ ① これは β です🧪
公式ドキュメントでも Replay protection (beta) と明記されています。(Firebase)
✅ ② 「CallableのReplay protection」は Node.js のFunctions SDKだけ対応🍃
ドキュメントに “Node.js の Cloud Functions SDK のみ対応” とあります。(Firebase) つまり、Python(preview)や他言語のCallable では同じやり方はできません(この章では Node/TS で固めるのが安全ルートです🚶♂️)。
✅ ③ 速度コストがある(追加の往復が増える)🐢

Replay protection をONにすると App Checkバックエンドへの追加通信が発生して遅延が増えるので、普通は 重要なエンドポイントだけに使います。(Firebase)
3) このミニアプリだと「どこに入れる?」🎯🤖

題材アプリ「メモ+画像+AI整形」だと、Replay protection はここが鉄板です👇
- AI整形ボタン(Firebase AI Logic / Gemini呼び出し) → 連打・自動化されると コストが燃える🔥
- 管理者専用のCallable(削除/凍結/大量処理) → 事故が怖い😱
逆に、毎回呼ばれる高頻度API に雑に入れると、体感が遅くなってUXが死にます🪦 (“全部ONにしない”が正解です💡)
4) ハンズオン:Callable FunctionsでReplay protectionを有効化☎️🧿
ここでは 2nd gen(v2) の書き方でいきます✍️
第10章で enforceAppCheck: true を入れている前提で、そこに consumeAppCheckToken: true を追加します。
✅ 4-1. Functions側:consumeAppCheckToken: true を付ける

// functions/src/index.ts
import { onCall, HttpsError } from "firebase-functions/v2/https";
export const aiFormatMemo = onCall(
{
enforceAppCheck: true, // App Checkが無い/無効なら拒否 🧿
consumeAppCheckToken: true, // ★ 使い捨て(リプレイ防止)♻️🚫
},
async (request) => {
// request.app に App Check情報(appIdなど)が入るよ 🧩
// request.auth にはAuth情報(ログインしていれば)👤
if (!request.auth) {
throw new HttpsError("unauthenticated", "ログインしてね🙂");
}
// ここでAI整形(例:Firebase AI Logic / Gemini)を呼ぶ想定 🤖
// ...(第12章でガッツリやる)
return { ok: true };
}
);
この consumeAppCheckToken が、公式で案内されている “Replay protection のスイッチ” です。(Firebase)
✅ 4-2. 役割(IAMロール)を付ける🔑👮
Replay protection を使うには、トークンを検証するサービスアカウントに
Firebase App Check Token Verifier ロールが必要です。(Firebase)
どのサービスアカウントかは構成で変わります👇(公式に分岐が書かれています)
- 1st gen のデフォルト構成 → App Engine default service account
- 2nd gen のデフォルト構成 → Default compute service account (Firebase)
(Admin SDK を明示初期化していて、専用のサービスアカウントキーを使ってるなら、最初から付与済みのこともあります。(Firebase))
✅ 4-3. React側:Callable呼び出しで “limited-use” を要求する⚛️🧾

// src/lib/functions.ts
import { getFunctions, httpsCallable } from "firebase/functions";
export async function callAiFormatMemo() {
const fn = httpsCallable(
getFunctions(),
"aiFormatMemo",
{ limitedUseAppCheckTokens: true } // ★ 使い捨てトークンで呼ぶ🧿♻️
);
const res = await fn({ text: "こんにちは!" });
return res.data;
}
これを付けないと、サーバ側で「使い捨て前提」になってるのに、クライアントが通常トークンで来て 401/Permission denied っぽい挙動になって詰まりがちです😵💫 (“サーバだけON” はだいたい事故ります)
5) 仕組みを腹落ちさせる:流れを図解っぽく🧿➡️♻️➡️🚫
-
通常モード
- クライアント:トークンを取る
- サーバ:検証してOKなら処理
- 同じトークンでも、期限内ならまた通る可能性あり
-
Replay protection モード(この章)
- クライアント:limited-useトークンを取る
- サーバ:検証して consume(消費)
- 同じトークンで再実行 → “もう使ったよ”で拒否🚫
この「サーバが consume する」がポイントです。(Firebase)
6) “AI機能”と絡めた現実の防御線🤖🛡️

Replay protection は強いけど、万能ではないです🙂 「同じトークンの使い回し」を止めるだけなので、
- 攻撃者が毎回あらたにトークンを取って
- 何回も正規っぽく叩く
みたいなケースは別対策も必要です🧯
Firebase公式ブログのAIエンドポイント例でも、Replay protection(consume)に加えて **認証(Auth)**や レート制限も一緒にやっています。(The Firebase Blog)
つまり結論: Replay protection + Auth + レート制限(/クォータ) が “お財布防衛ライン” です💸🛡️
7) Antigravity / Gemini CLI で爆速チェックするアイデア🚀🤖🔎
ここ、AIと相性めちゃ良いです👇
-
Gemini CLI にリポジトリを見せて
httpsCallable(を全部探させる- 「どの呼び出しだけ
limitedUseAppCheckTokens: trueにするべき?」を分類させる🎯
-
Antigravity のエージェントに
- “管理者操作・AI操作・課金が絡む操作” を洗い出し
- 「Replay protection 対象リスト」を作らせる🧾✨
-
さらに「ONにしたら遅くなる箇所」も候補に出させて、UX事故を予防🙂⚖️
(AIにやらせるのは “洗い出し・提案・差分作成” まで。最終判断は人間が握るのが安全です👍)
8) ミニ課題📝🔥
-
あなたのミニアプリで 「絶対に使い回しされたくないCallable」 を2つ選ぶ🎯
- 例:AI整形、管理者削除、課金に近い操作…など
-
その2つだけに
consumeAppCheckToken: trueを付ける♻️ -
React側もその2つだけ
limitedUseAppCheckTokens: trueにする⚛️
9) チェック✅(ここまでできたら勝ち!🏁)
consumeAppCheckToken: trueを 重要なCallableだけに入れた♻️🚫 (Firebase)- React側で、そのCallableだけ
limitedUseAppCheckTokens: trueを付けた⚛️🧾 (Firebase) - IAMの
Firebase App Check Token Verifierロールの話を理解した🔑👮 (Firebase) - 「全部ONにしない(遅延が増える)」が説明できる🐢⚖️ (Firebase)
- 「Replayだけじゃ財布攻撃は止まらない→Auth/レート制限も必要」が言える💸🧯 (The Firebase Blog)
次の第12章(AIを守る)では、この章で作った “AI整形Callable” を本当にAI接続して、 App Check + (必要なら)ユーザー単位の回数制御までセットで「破産しないAI」に仕上げます🤖💸🛡️