Özel bir arka uçtan Uygulama Kontrolü jetonlarını doğrulama

Uygulamanızın kendi bünyesinde barındırılan arka uçlar gibi Firebase dışı kaynaklarını koruyabilirsiniz. kullanıma sunduk. Bunun için aşağıdakilerin ikisini de yapmanız gerekir:

  • Uygulama istemcinizi her istekle birlikte bir Uygulama Kontrolü jetonu gönderecek şekilde değiştirme ilgili sayfalarda açıklandığı gibi, arka ucunuza iOS+, Android ve web
  • Arka ucunuzu her istekte geçerli bir uygulama kontrolü jetonu gerektirecek şekilde değiştirin. bu sayfada açıklandığı gibidir.

Jeton doğrulama

Arka ucunuzdaki Uygulama Kontrolü jetonlarını doğrulamak için API uç noktalarınıza mantık ekleyin şunları yapar:

  • Her isteğin bir Uygulama Kontrolü jetonu içerdiğinden emin olun.

  • Admin SDK'yı kullanarak Uygulama Kontrolü jetonunu doğrulayın.

    Doğrulama başarılı olursa Yönetici SDK'sı kodu çözülmüş Uygulama Kontrolü'nü döndürür jeton. Doğrulama başarılı olursa jetonun kaynağı bir uygulamadır Firebase projenize ait.

İki denetimden de geçemeyen istekleri reddedin. Örneğin:

Node.js

Henüz Node.js Admin SDK'sını yüklemediyseniz lütfen unutmayın.

Ardından, örnek olarak Express.js ara katman 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

Henüz Python Admin SDK'sını yüklemediyseniz lütfen unutmayın.

Ardından API uç nokta işleyicilerinizde app_check.verify_token() komutunu çağırın ve isteği reddeder. Aşağıdaki örnekte, @before_request ile süslenmiş, tüm istekler için bu görevi 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.
    ...

Go

Go için Admin SDK'yı henüz yüklemediyseniz lütfen unutmayın.

Ardından, API uç nokta işleyicilerinizde appcheck.Client.VerifyToken() komutunu çağırın ve başarısız olursa isteği reddeder. Aşağıdaki örnekte sarmalayıcı, işlevi, şu mantığı uç nokta işleyicilere 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 arka ucunuz başka bir dilde yazılmışsa şurada bulunan gibi genel amaçlı bir JWT kütüphanesi: jwt.io: Uygulama Kontrolü jetonlarını doğrulamak için kullanılır.

Jeton doğrulama mantığınız aşağıdaki adımları tamamlamalıdır:

  1. Uygulamadan Firebase Uygulama Kontrolü'nün herkese açık JSON Web Anahtarı (JWK) Setini edinme JWKS uç noktasını kontrol edin: https://firebaseappcheck.googleapis.com/v1/jwks.
  2. Geçerli olduğundan emin olmak için Uygulama Kontrolü jetonunun imzasını doğrulayın.
  3. Jeton başlığının RS256 algoritmasını kullandığından emin olun.
  4. Jetonun başlığının JWT türünde olduğundan emin olun.
  5. Jetonun belirler.
  6. Jetonun süresinin dolmadığından emin olun.
  7. Jetonun kitlesinin projenizle eşleştiğinden emin olun.
  8. İsteğe bağlı: Jetonun konusunun, uygulamanızın uygulama kimliğiyle eşleştiğinden emin olun.

JWT kitaplıklarının özellikleri farklılık gösterebilir; manuel olarak tamamladığınızdan seçtiğiniz kitaplık tarafından işlenmeyen tüm adımlar.

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

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ından korumak için Uygulama Kontrolü jetonunu kullanabilirsiniz kullanılabilmesi için doğrulama işleminden sonra kullanılabilmesidir.

Tekrar oynatma korumasını kullanmak, verifyToken() cihazına gidiş dönüş ağ ekler çağrısı yapar ve bu nedenle, bu çağrıyı kullanan tüm uç noktalara gecikme ekler. İşte bu nedenle tekrar oynatma korumasını yalnızca özellikle hassas olan uç noktalar.

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

  1. Cloud Console, "Firebase Uygulama Kontrol Jetonu Doğrulayıcı"yı verin rolünü etkinleştirmelisiniz. jetonları doğrulamak için kullanılır.

    • Yönetici SDK'sını Yönetici SDK'sı hizmet hesabıyla başlattıysanız Firebase konsolundan indirdiğiniz kimlik bilgilerini kullanıyorsanız, gereken rol: zaten verildi.
    • 1. nesil Cloud Functions'ı varsayılan Yönetici ayarıyla kullanıyorsanız SDK yapılandırması, rolü App Engine varsayılan hizmetine verin hesap. Hizmet hesabı izinlerini değiştirme başlıklı makaleyi inceleyin.
    • Varsayılan Yönetici ayarıyla 2. nesil Cloud Functions'ı kullanıyorsanız SDK yapılandırması, rolü Varsayılan bilgi işlem hizmeti hesap.
  2. Ardından, bir jetonu kullanmak için { consume: true } öğesini verifyToken() öğesine iletin yöntemini kullanın ve sonuç nesnesini inceleyin; alreadyConsumed özelliği true, isteği reddedin veya bir tür düzeltici eylemde bulunun. Örneğin, arayan kişinin diğer kontrolleri geçmesini istemek.

    Ö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 işlem, jetonu doğrular ve ardından kullanıldı olarak işaretler. Gelecekteki çağrılar %50'si aynı jeton üzerindeverifyToken(appCheckToken, { consume: true }) alreadyConsumed öğesini true olarak ayarla. (verifyToken() işlevinin tüketilen bir jetonu reddetmediğini ve hatta consume ayarlanmazsa kullanılır.)

Bu özelliği belirli bir uç nokta için etkinleştirdiğinizde ayrıca uç nokta. Aşağıdakilerle ilgili istemci taraflı dokümanlara bakın: Apple platformları Android ve web