Sie können die nicht Firebase-Ressourcen Ihrer App, z. B. selbst gehostete Backends, mit App Check schützen. Dazu müssen Sie Folgendes tun:
- Ändern Sie Ihren App-Client so, dass er 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 für jede Anfrage ein gültiges App Check-Token erforderlich ist, wie auf dieser Seite beschrieben.
Tokenüberprüfung
Wenn Sie App Check-Token in Ihrem Backend prüfen möchten, fügen Sie Ihren API-Endpunkten Logik hinzu, die Folgendes tut:
Prüfen Sie, ob jede Anfrage ein App Check-Token enthält.
Prüfe das App Check-Token mit dem Admin SDK.
Wenn die Überprüfung erfolgreich ist, gibt das Admin SDK das decodierte App Check-Token zurück. Eine erfolgreiche Bestätigung bedeutet, dass das Token aus einer App stammt, die zu Ihrem Firebase-Projekt gehört.
Alle Anfragen, die eine der Prüfungen nicht bestehen, werden abgelehnt. Beispiel:
Node.js
Installieren Sie das Node.js Admin SDK, falls noch nicht geschehen.
Anhand der Express.js-Middleware:
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
Installieren Sie das Python Admin SDK, falls noch nicht geschehen.
Rufen Sie dann in Ihren API-Endpunkt-Handlern app_check.verify_token()
auf und lehnen Sie die Anfrage ab, falls sie fehlschlägt. Im folgenden Beispiel führt eine mit @before_request
verzierte 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.
...
Go
Installieren Sie das Admin SDK für Go, falls noch nicht geschehen.
Rufen Sie dann in Ihren API-Endpunkt-Handlern appcheck.Client.VerifyToken()
auf und lehnen Sie die Anfrage ab, falls sie fehlschlägt. Im folgenden Beispiel wird diese Logik den Endpunkt-Handlern über eine Wrapperfunktion hinzugefügt:
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.
}
Sonstiges
Wenn Ihr Backend in einer anderen Sprache geschrieben ist, können Sie eine allgemeine JWT-Bibliothek wie die unter jwt.io finden, um App Check-Tokens zu überprüfen.
Die Logik zur Tokenbestätigung muss die folgenden Schritte ausführen:
- Rufen Sie den öffentlichen JSON-Webschlüsselsatz (JWK) von Firebase App Check über den JWKS-Endpunkt von App Check ab:
https://firebaseappcheck.googleapis.com/v1/jwks
- Prüfen Sie die Signatur des App Check-Tokens, um sicherzustellen, dass es legitim ist.
- Der Header des Tokens muss den Algorithmus RS256 verwenden.
- Der Header des Tokens muss den Typ „JWT“ haben.
- Das Token muss von Firebase App Check für Ihr Projekt ausgestellt werden.
- Prüfen Sie, ob das Token abgelaufen ist.
- Die Zielgruppe des Tokens muss mit Ihrem Projekt übereinstimmen.
- Optional: Prüfen Sie, ob der Betreff des Tokens mit der App-ID Ihrer App übereinstimmt.
Die Funktionen von JWT-Bibliotheken können sich unterscheiden. Führe alle Schritte, die von der ausgewählten Bibliothek nicht ausgeführt werden, manuell aus.
Im folgenden Beispiel werden die erforderlichen Schritte in Ruby mit dem jwt
-Gem 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
Replay-Schutz (Beta)
Um einen Endpunkt vor Replay-Angriffen zu schützen, können Sie das App Check-Token nach der Überprüfung verwenden, damit es nur einmal verwendet werden kann.
Wenn Sie den Replay-Schutz verwenden, wird dem verifyToken()
-Aufruf ein Netzwerk-Roundtrip hinzugefügt, was die Latenz für jeden Endpunkt erhöht, der ihn verwendet. Aus diesem Grund empfehlen wir, den Replay-Schutz nur für besonders sensible Endpunkte zu aktivieren.
So verwenden Sie den Replay-Schutz:
Weisen Sie in der Cloud Console dem Dienstkonto, das zum Verifizieren von Tokens verwendet wird, die Rolle „Firebase App Check Token Verifier“ zu.
- Wenn Sie das Admin SDK mit den Anmeldedaten des Admin SDK-Dienstkontos initialisiert haben, die Sie aus der Firebase Console heruntergeladen haben, wurde die erforderliche Rolle bereits gewährt.
- Wenn Sie Cloud Functions der 1. Generation mit der Standardkonfiguration des Admin SDK verwenden, gewähren Sie die Rolle dem App Engine-Standarddienstkonto. Weitere Informationen finden Sie unter Dienstkontoberechtigungen ändern.
- Wenn Sie Cloud Functions der 2. Generation mit der Standardkonfiguration des Admin SDK verwenden, weisen Sie die Rolle dem Compute-Standarddienstkonto zu.
Wenn du ein Token verwenden möchtest, übergebe
{ consume: true }
an die MethodeverifyToken()
und prüfe das Ergebnisobjekt. Wenn diealreadyConsumed
-Eigenschafttrue
ist, lehne die Anfrage ab oder führe eine Korrekturmaßnahme durch, z. B. indem du den Aufrufer aufforderst, andere Prüfungen zu bestehen.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 verifiziert und dann als verbraucht gekennzeichnet. Bei zukünftigen Aufrufen von
verifyToken(appCheckToken, { consume: true })
für dasselbe Token wirdalreadyConsumed
auftrue
gesetzt. Hinweis:verifyToken()
lehnt ein bereits verwendetes Token nicht ab und prüft auch nicht, ob es bereits verwendet wurde, wennconsume
nicht festgelegt ist.
Wenn Sie diese Funktion für einen bestimmten Endpunkt aktivieren, müssen Sie auch Ihren App-Clientcode aktualisieren, um Verbrauchs-Tokens mit begrenzter Verwendung für den Endpunkt zu erwerben. Weitere Informationen finden Sie in der clientseitigen Dokumentation für Apple-Plattformen, Android und Web.