Google I/O 2023 での Firebase の最新情報。詳細

カスタム バックエンドから App Check トークンを検証する

App Check では、アプリで使用する Firebase 以外のリソース(セルフホスト バックエンドなど)も保護できます。そのためには、次の両方を行う必要があります。

  • iOS+Androidウェブのページで説明するように、バックエンドへのリクエストと一緒に App Check トークンを送信するようにアプリ クライアントを変更します。
  • このページで説明するように、すべてのリクエストで有効な App Check トークンを要求するようにバックエンドを変更します。

始める前に

Node.js Admin SDK をまだインストールしていない場合は、インストールします。

トークンを検証する

バックエンドの App Check トークンを確認するには、次の処理を行うロジックを API エンドポイントに追加します。

  • 各リクエストに App Check トークンが含まれていることを確認します。

  • Admin SDK の appCheck().verifyToken() メソッドを使用して App Check トークンを検証します。

    検証に成功すると、verifyToken() はデコードされた App Check トークンを返します。検証に成功した場合、Firebase プロジェクトに属するアプリからトークンが取得されたことを意味します。

いずれかのチェックに合格しなかったリクエストは拒否されます。たとえば、Express.js ミドルウェアを使用する場合は、次のようになります。

const express = require('express');
const app = express();

const { initializeApp } = require("firebase-admin/app");
const { getAppCheck } = require("firebase-admin/app-check");
const firebaseApp = initializeApp();

const appCheckVerification = async (req, res, next) => {
    const appCheckToken = req.header('X-Firebase-AppCheck');

    if (!appCheckToken) {
        res.status(401);
        return next('Unauthorized');
    }

    try {
        const appCheckClaims = await getAppCheck().verifyToken(appCheckToken);

        // If verifyToken() succeeds, continue with the next middleware
        // function in the stack.
        return next();
    } catch (err) {
        res.status(401);
        return next('Unauthorized');
    }
}

app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => {
    // Handle request.
});

リプレイ保護(ベータ版)

リプレイ攻撃からエンドポイントを保護するために、App Check トークンを検証後に使用済みにし、一度しか使用できないようにすることができます。

リプレイ保護を使用すると、verifyToken() 呼び出しにネットワークのラウンド トリップが一つ追加されるため、リプレイ保護を使用するすべてのエンドポイントでレイテンシが増加します。このため、リプレイ保護は特に機密性の高いエンドポイントのみで有効にすることをおすすめします。

リプレイ保護を使用するには、まず、Admin SDK で使用しているサービス アカウントで IAM ロール「Firebase App Check トークン検証者」が有効になっている必要があります。Cloud Functions の場合、これは通常デフォルトのコンピューティング サービス アカウントです。他のプラットフォームの場合は、通常 Admin SDK サービス アカウントです。IAM ロールは Cloud コンソールで有効にすることができます。

次に、トークンを消費するため { consume: true }verifyToken() メソッドに渡し、結果オブジェクトを調べます。alreadyConsumed プロパティが true の場合は、リクエストを拒否するか、なんらかの対応処理(呼び出し元に他のチェックを満たすことを要求するなど)を行います。

次に例を示します。

const appCheckClaims = await getAppCheck().verifyToken(appCheckToken, { consume: true });

if (appCheckClaims.alreadyConsumed) {
    res.status(401);
    return next('Unauthorized');
}

// If verifyToken() succeeds and alreadyConsumed is not set, okay to continue.

このコードでは、トークンの確認が行われ、その後でトークンに使用済みのフラグが付けられます。今後、同じトークンに対して verifyToken(appCheckToken, { consume: true }) が呼び出されると、alreadyConsumedtrue に設定されます(consume が設定されていない場合、verifyToken() は使用済みトークンを拒否せず、トークンが使用済みかどうかの確認も行いません)。

特定のエンドポイントでこの機能を有効にするには、そのエンドポイントで使用済みにできる限定使用のトークンを取得するようにアプリのクライアント コードを変更する必要があります。Apple プラットフォームAndroidウェブのクライアントサイドのドキュメントをご覧ください。