Mit App Check können Sie die Nicht-Firebase-Ressourcen Ihrer App, z. B. selbstgehostete Backends, schützen. Dazu müssen Sie beide der folgenden Schritte ausführen:
- Ändern Sie Ihren App-Client so, dass er zusammen mit jeder Anfrage ein App-Check-Token an Ihr Backend sendet, wie auf den Seiten für iOS+ , Android und Web beschrieben.
- Ändern Sie Ihr Backend so, dass bei jeder Anfrage ein gültiges App Check-Token erforderlich ist, wie auf dieser Seite beschrieben.
Token-Verifizierung
Um App Check-Tokens in Ihrem Backend zu überprüfen, fügen Sie Ihren API-Endpunkten eine Logik hinzu, die Folgendes bewirkt:
Stellen Sie sicher, dass jede Anfrage ein App Check-Token enthält.
Überprüfen Sie das App Check-Token mit dem Admin SDK.
Wenn die Überprüfung erfolgreich ist, gibt das Admin SDK das entschlüsselte App Check-Token zurück. Eine erfolgreiche Überprüfung zeigt an, dass das Token von einer App stammt, die zu Ihrem Firebase-Projekt gehört.
Lehnen Sie jede Anfrage ab, die eine der beiden Prüfungen nicht besteht. Zum Beispiel:
Node.js
Wenn Sie das Node.js Admin SDK noch nicht installiert haben, tun Sie dies.
Verwenden Sie dann die Express.js-Middleware als Beispiel:
import express from "express";
import { initializeApp } from "firebase-admin/app";
import { getAppCheck } from "firebase-admin/app-check";
const expressApp = express();
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");
}
}
expressApp.get("/yourApiEndpoint", [appCheckVerification], (req, res) => {
// Handle request.
});
Python
Wenn Sie das Python Admin SDK noch nicht installiert haben, tun Sie dies.
Rufen Sie dann in Ihren API-Endpunkt-Handlern app_check.verify_token()
auf und lehnen Sie die Anfrage ab, wenn sie fehlschlägt. Im folgenden Beispiel führt eine mit @before_request
dekorierte Funktion diese Aufgabe für alle Anfragen aus:
import firebase_admin
from firebase_admin import app_check
import flask
import jwt
firebase_app = firebase_admin.initialize_app()
flask_app = flask.Flask(__name__)
@flask_app.before_request
def verify_app_check() -> None:
app_check_token = flask.request.headers.get("X-Firebase-AppCheck", default="")
try:
app_check_claims = app_check.verify_token(app_check_token)
# If verify_token() succeeds, okay to continue to route handler.
except (ValueError, jwt.exceptions.DecodeError):
flask.abort(401)
@flask_app.route("/yourApiEndpoint")
def your_api_endpoint(request: flask.Request):
# Handle request.
...
Gehen
Wenn Sie das Admin SDK für Go noch nicht installiert haben, tun Sie dies.
Rufen Sie dann in Ihren API-Endpunkt-Handlern appcheck.Client.VerifyToken()
auf und lehnen Sie die Anfrage ab, wenn sie fehlschlägt. Im folgenden Beispiel fügt eine Wrapper-Funktion diese Logik zu den Endpunkt-Handlern hinzu:
package main
import (
"context"
"log"
"net/http"
firebaseAdmin "firebase.google.com/go/v4"
"firebase.google.com/go/v4/appcheck"
)
var (
appCheck *appcheck.Client
)
func main() {
app, err := firebaseAdmin.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
appCheck, err = app.AppCheck(context.Background())
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
http.HandleFunc("/yourApiEndpoint", requireAppCheck(yourApiEndpointHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
func requireAppCheck(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
wrappedHandler := func(w http.ResponseWriter, r *http.Request) {
appCheckToken, ok := r.Header[http.CanonicalHeaderKey("X-Firebase-AppCheck")]
if !ok {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized."))
return
}
_, err := appCheck.VerifyToken(appCheckToken[0])
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized."))
return
}
// If VerifyToken() succeeds, continue with the provided handler.
handler(w, r)
}
return wrappedHandler
}
func yourApiEndpointHandler(w http.ResponseWriter, r *http.Request) {
// Handle request.
}
Andere
Wenn Ihr Backend in einer anderen Sprache geschrieben ist, können Sie eine universelle JWT-Bibliothek verwenden, z. B. eine unter jwt.io , um App Check-Tokens zu überprüfen.
Ihre Token-Verifizierungslogik muss die folgenden Schritte ausführen:
- Rufen Sie den öffentlichen JSON Web Key (JWK)-Satz für Firebase App Check vom App Check JWKS-Endpunkt ab:
https://firebaseappcheck.googleapis.com/v1/jwks
- Überprüfen Sie die Signatur des App Check-Tokens, um sicherzustellen, dass es legitim ist.
- Stellen Sie sicher, dass der Header des Tokens den Algorithmus RS256 verwendet.
- Stellen Sie sicher, dass der Header des Tokens den Typ JWT hat.
- Stellen Sie sicher, dass das Token von Firebase App Check für Ihr Projekt ausgestellt wird.
- Stellen Sie sicher, dass das Token nicht abgelaufen ist.
- Stellen Sie sicher, dass die Zielgruppe des Tokens mit Ihrem Projekt übereinstimmt.
- Optional : Überprüfen Sie, ob der Betreff des Tokens mit der App-ID Ihrer App übereinstimmt.
Die Funktionen von JWT-Bibliotheken können unterschiedlich sein; Stellen Sie sicher, dass Sie alle Schritte manuell ausführen, die nicht von der von Ihnen ausgewählten Bibliothek ausgeführt werden.
Im folgenden Beispiel werden die erforderlichen Schritte in Ruby unter Verwendung des jwt
Gems als Rack-Middleware-Ebene ausgeführt.
require 'json'
require 'jwt'
require 'net/http'
require 'uri'
class AppCheckVerification
def initialize(app, options = {})
@app = app
@project_number = options[:project_number]
end
def call(env)
app_id = verify(env['HTTP_X_FIREBASE_APPCHECK'])
return [401, { 'Content-Type' => 'text/plain' }, ['Unauthenticated']] unless app_id
env['firebase.app'] = app_id
@app.call(env)
end
def verify(token)
return unless token
# 1. Obtain the Firebase App Check Public Keys
# Note: It is not recommended to hard code these keys as they rotate,
# but you should cache them for up to 6 hours.
uri = URI('https://firebaseappcheck.googleapis.com/v1/jwks')
jwks = JSON(Net::HTTP.get(uri))
# 2. Verify the signature on the App Check token
payload, header = JWT.decode(token, nil, true, jwks: jwks, algorithms: 'RS256')
# 3. Ensure the token's header uses the algorithm RS256
return unless header['alg'] == 'RS256'
# 4. Ensure the token's header has type JWT
return unless header['typ'] == 'JWT'
# 5. Ensure the token is issued by App Check
return unless payload['iss'] == "https://firebaseappcheck.googleapis.com/#{@project_number}"
# 6. Ensure the token is not expired
return unless payload['exp'] > Time.new.to_i
# 7. Ensure the token's audience matches your project
return unless payload['aud'].include? "projects/#{@project_number}"
# 8. The token's subject will be the app ID, you may optionally filter against
# an allow list
payload['sub']
rescue
end
end
class Application
def call(env)
[200, { 'Content-Type' => 'text/plain' }, ["Hello app #{env['firebase.app']}"]]
end
end
use AppCheckVerification, project_number: 1234567890
run Application.new
Wiedergabeschutz (Beta)
Um einen Endpunkt vor Replay-Angriffen zu schützen, können Sie das App Check-Token nach der Überprüfung nutzen, sodass es nur einmal verwendet werden kann.
Durch die Verwendung des Wiedergabeschutzes wird ein Netzwerk-Roundtrip zum verifyToken()
Aufruf hinzugefügt und somit die Latenz für jeden Endpunkt erhöht, der ihn verwendet. Aus diesem Grund empfehlen wir, den Wiedergabeschutz nur auf besonders sensiblen Endpunkten zu aktivieren.
Um den Wiedergabeschutz zu verwenden, gehen Sie wie folgt vor:
Weisen Sie in der Cloud-Konsole dem Dienstkonto, das zur Überprüfung von Tokens verwendet wird, die Rolle „Firebase App Check Token Verifier“ zu.
- Wenn Sie das Admin SDK mit den Anmeldeinformationen des Admin SDK-Dienstkontos initialisiert haben, die Sie von der Firebase-Konsole heruntergeladen haben, ist die erforderliche Rolle bereits gewährt.
- Wenn Sie Cloud Functions der 1. Generation mit der standardmäßigen Admin SDK-Konfiguration verwenden, weisen Sie die Rolle dem App Engine-Standarddienstkonto zu. Siehe Dienstkontoberechtigungen ändern .
- Wenn Sie Cloud Functions der 2. Generation mit der Standard-Admin-SDK-Konfiguration verwenden, weisen Sie die Rolle dem Standard-Rechendienstkonto zu.
Um dann ein Token zu konsumieren, übergeben Sie
{ consume: true }
an die MethodeverifyToken()
und untersuchen Sie das Ergebnisobjekt. Wenn die EigenschaftalreadyConsumed
“ den Wert „true
hat, lehnen Sie die Anfrage ab oder ergreifen Sie eine Korrekturmaßnahme, z. B. indem Sie den Aufrufer auffordern, weitere Prüfungen zu bestehen.Zum Beispiel:
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.
Dadurch wird das Token überprüft und dann als verbraucht gekennzeichnet. Zukünftige Aufrufe von
verifyToken(appCheckToken, { consume: true })
für dasselbe Token setzen „alreadyConsumed
auf „true
. (Beachten Sie, dassverifyToken()
ein verbrauchtes Token nicht ablehnt und nicht einmal prüft, ob es verbraucht ist, wennconsume
nicht festgelegt ist.)
Wenn Sie diese Funktion für einen bestimmten Endpunkt aktivieren, müssen Sie auch Ihren App-Clientcode aktualisieren, um verbrauchbare Token mit begrenzter Nutzung für die Verwendung mit dem Endpunkt zu erwerben. Sehen Sie sich die clientseitigen Dokumente für Apple-Plattformen , Android und Web an.