Özel bir arka uçtan Uygulama Kontrolü belirteçlerini doğrulayın

Uygulamanızın, şirket içinde barındırılan arka uçlar gibi Firebase dışı kaynaklarını Uygulama Kontrolü ile koruyabilirsiniz. Bunu yapmak için aşağıdakilerden ikisini de yapmanız gerekir:

  • Uygulama istemcinizi , iOS+ , Android ve web sayfalarında açıklandığı gibi, her istekle birlikte arka ucunuza bir Uygulama Kontrolü jetonu gönderecek şekilde değiştirin.
  • Bu sayfada açıklandığı gibi, her istekte geçerli bir Uygulama Kontrolü jetonu gerektirecek şekilde arka ucunuzu değiştirin.

Jeton doğrulaması

Arka ucunuzdaki Uygulama Kontrolü belirteçlerini doğrulamak için API uç noktalarınıza aşağıdakileri yapan mantık ekleyin:

  • Her isteğin bir Uygulama Kontrolü jetonu içerdiğini kontrol edin.

  • Yönetici SDK'sını kullanarak Uygulama Kontrolü jetonunu doğrulayın.

    Doğrulama başarılı olursa Yönetici SDK'sı kodu çözülmüş Uygulama Kontrolü belirtecini döndürür. Başarılı doğrulama, jetonun Firebase projenize ait bir uygulamadan kaynaklandığını gösterir.

Her iki kontrolde de başarısız olan tüm istekleri reddedin. Örneğin:

Node.js

Henüz Node.js Yönetici SDK'sını yüklemediyseniz bunu yapın.

Daha sonra örnek olarak Express.js ara yazılımını kullanarak:

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

Python Admin SDK'yı henüz yüklemediyseniz bunu yapın.

Ardından API uç nokta işleyicilerinizde app_check.verify_token() öğesini çağırın ve başarısız olursa isteği reddedin. Aşağıdaki örnekte, @before_request ile süslenmiş bir işlev bu görevi tüm istekler için gerçekleştirir:

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.
    ...

Gitmek

Go için Yönetici SDK'sını henüz yüklemediyseniz bunu yapın.

Ardından API uç nokta işleyicilerinizde appcheck.Client.VerifyToken() öğesini çağırın ve başarısız olursa isteği reddedin. Aşağıdaki örnekte, bir sarmalayıcı işlevi bu mantığı uç nokta işleyicilerine ekler:

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.
}

Diğer

Arka ucunuz başka bir dilde yazılmışsa Uygulama Kontrolü belirteçlerini doğrulamak için jwt.io adresinde bulunanlar gibi genel amaçlı bir JWT kitaplığı kullanabilirsiniz.

Belirteç doğrulama mantığınızın aşağıdaki adımları tamamlaması gerekir:

  1. Firebase Uygulama Kontrolü genel JSON Web Anahtarı (JWK) Setini Uygulama Kontrolü JWKS uç noktasından edinin: https://firebaseappcheck.googleapis.com/v1/jwks
  2. Meşru olduğundan emin olmak için Uygulama Kontrolü jetonunun imzasını doğrulayın.
  3. Belirtecin başlığının RS256 algoritmasını kullandığından emin olun.
  4. Belirtecin başlığının JWT türünde olduğundan emin olun.
  5. Belirtecin projeniz kapsamında Firebase App Check tarafından verildiğinden emin olun.
  6. Belirtecin süresinin dolmadığından emin olun.
  7. Belirtecin hedef kitlesinin projenizle eşleştiğinden emin olun.
  8. İsteğe bağlı : Belirtecin konusunun uygulamanızın Uygulama Kimliğiyle eşleştiğini kontrol edin.

JWT kitaplıklarının yetenekleri farklılık gösterebilir; Seçtiğiniz kitaplığın işlemediği adımları manuel olarak tamamladığınızdan emin olun.

Aşağıdaki örnek, jwt gem'i Rack ara katman yazılımı katmanı olarak kullanarak Ruby'de gerekli adımları gerçekleştirir.

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

Tekrar oynatma koruması (beta)

Bir uç noktayı tekrar saldırılarına karşı korumak için Uygulama Kontrolü jetonunu yalnızca bir kez kullanılabilecek şekilde doğruladıktan sonra kullanabilirsiniz.

Tekrar korumanın kullanılması, verifyToken() çağrısına ağda bir gidiş dönüş ekler ve dolayısıyla onu kullanan tüm uç noktalara gecikme ekler. Bu nedenle tekrar oynatma korumasını yalnızca özellikle hassas uç noktalarda etkinleştirmenizi öneririz.

Tekrar oynatma korumasını kullanmak için aşağıdakileri yapın:

  1. Bulut konsolunda , jetonları doğrulamak için kullanılan hizmet hesabına "Firebase Uygulama Kontrol Jetonu Doğrulayıcı" rolünü atayın.

    • Yönetici SDK'sını Firebase konsolundan indirdiğiniz Yönetici SDK'sı hizmet hesabı kimlik bilgileriyle başlattıysanız gerekli rol zaten verilmiştir.
    • 1. nesil Cloud Functions'ı varsayılan Yönetici SDK yapılandırmasıyla kullanıyorsanız rolü App Engine varsayılan hizmet hesabına atayın. Bkz . Hizmet hesabı izinlerini değiştirme .
    • 2. nesil Bulut İşlevlerini varsayılan Yönetici SDK yapılandırmasıyla kullanıyorsanız rolü Varsayılan işlem hizmeti hesabına atayın.
  2. Daha sonra, bir belirteci kullanmak için, verifyToken() yöntemine { consume: true } iletin ve sonuç nesnesini inceleyin; alreadyConsumed özelliği true ise, isteği reddedin veya arayanın başka kontrollerden geçmesini istemek gibi bir tür düzeltici eylem gerçekleştirin.

    Örneğin:

    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.
    

    Bu, belirteci doğrular ve ardından tüketildiği şekilde işaretler. Aynı belirteç üzerinde verifyToken(appCheckToken, { consume: true }) işlevinin gelecekteki çağrıları, alreadyConsumed öğesini true olarak ayarlayacaktır. ( verifyToken() tüketilen bir belirteci reddetmediğini ve hatta consume ayarlanmamışsa tüketilip tüketilmediğini kontrol etmediğini unutmayın.)

Bu özelliği belirli bir uç nokta için etkinleştirdiğinizde, uç noktayla birlikte kullanılmak üzere sınırlı kullanımlı sarf malzemeleri elde etmek için uygulama istemci kodunuzu da güncellemeniz gerekir. Apple platformları , Android ve web için istemci tarafı dokümanlarına bakın.