Uygulamanızın Firebase dışındaki kaynaklarını (ör. kendi kendine barındırılan arka uçlar) App Check ile koruyabilirsiniz. Bunun için aşağıdakilerin ikisini birden yapmanız gerekir:
- Uygulama istemcinizi, iOS+, Android ve web sayfalarında açıklandığı gibi arka uçunuza her istekle birlikte bir App Check jetonu gönderecek şekilde değiştirin.
- Arka uçunuzu, bu sayfada açıklandığı gibi her istek için geçerli bir App Check jetonu gerektirecek şekilde değiştirin.
Jeton doğrulaması
Arka uçta App Check jetonlarını doğrulamak için API uç noktalarınıza aşağıdakileri yapan bir mantık ekleyin:
Her isteğin bir App Check jetonu içerdiğinden emin olun.
Yönetici SDK'sını kullanarak App Check jetonunu doğrulayın.
Doğrulama başarılı olursa Yönetici SDK'sı, kodu çözülmüş App Check jetonunu döndürür. Doğrulama işleminin başarılı olması, jetonun Firebase projenize ait bir uygulamadan geldiğini gösterir.
Her iki kontrolde de başarısız olan istekler reddedilir. Örneğin:
Node.js
Node.js Admin SDK'yı henüz yüklemediyseniz yükleyin.
Ardından, Express.js ara yazılımını örnek olarak 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'yı yüklemediyseniz yükleyin.
Ardından, API uç noktası işleyicilerinizde app_check.verify_token()
işlevini çağırın ve başarısız olursa isteği reddedin. Aşağıdaki örnekte, @before_request
ile süslenmiş bir işlev 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
Henüz Go için Yönetici SDK'sını yüklemediyseniz yükleyin.
Ardından, API uç noktası işleyicilerinizde appcheck.Client.VerifyToken()
işlevini çağırın ve başarısız olursa isteği reddedin. Aşağıdaki örnekte, bir sarmalayıcı işlevi uç nokta işleyicilerine aşağıdaki mantığı 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 uçunuz başka bir dilde yazılmışsa App Check jetonlarını doğrulamak için jwt.io adresinde bulunanlar gibi genel amaçlı bir JWT kitaplığı kullanabilirsiniz.
Jeton doğrulama mantığınız aşağıdaki adımları tamamlamalıdır:
- AppCheck JWKS uç noktasından Firebase AppCheck herkese açık JSON Web Anahtarı (JWK) kümesini alın:
https://firebaseappcheck.googleapis.com/v1/jwks
- Uygulama Kontrolü jetonunun imzasını doğrulayarak meşru olduğundan emin olun.
- Jetonun başlığında RS256 algoritmasının kullanıldığından emin olun.
- Jetonun başlığının JWT türüne sahip olduğundan emin olun.
- Jetonun, projeniz kapsamında Firebase Uygulama Kontrolü tarafından yayınlandığından emin olun.
- Jetonun geçerlilik süresinin dolmadığından emin olun.
- Jetonun kitlesinin projenizle eşleştiğinden emin olun.
- İsteğe bağlı: Jetonun öznesinin, uygulamanızın uygulama kimliğiyle eşleştiğinden emin olun.
JWT kitaplıklarının özellikleri farklılık gösterebilir. Seçtiğiniz kitaplık tarafından yönetilmeyen adımları manuel olarak tamamladığınızdan emin olun.
Aşağıdaki örnekte, Rack orta katmanı olarak jwt
gem'i kullanarak Ruby'de gerekli adımlar uygulanmaktadır.
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 koruması (beta)
Bir uç noktayı yeniden oynatma saldırılarına karşı korumak için App Check jetonunu doğruladıktan sonra yalnızca bir kez kullanılacak şekilde tüketebilirsiniz.
Tekrar oynatma koruması kullanıldığında verifyToken()
çağrıya bir ağ gidiş dönüş işlemi eklenir ve bu nedenle, bu korumayı kullanan tüm uç noktalara gecikme eklenir. Bu nedenle, yeniden oynatma korumasını yalnızca özellikle hassas uç noktalarda etkinleştirmenizi öneririz.
Tekrar oynatma korumasını kullanmak için aşağıdakileri yapın:
Cloud Console'da, jetonları doğrulamak için kullanılan hizmet hesabına "Firebase App Check Token Verifier" rolünü verin.
- Admin SDK'yı, Firebase konsolundan indirdiğiniz Admin SDK 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 verin. Hizmet hesabı izinlerini değiştirme başlıklı makaleyi inceleyin.
- 2. nesil Cloud Functions'ı varsayılan Yönetici SDK yapılandırmasıyla kullanıyorsanız rolü Varsayılan bilgi işlem hizmet hesabına verin.
Ardından, jetonu kullanmak için
{ consume: true }
değeriniverifyToken()
yöntemine iletin ve sonuç nesnesini inceleyin.alreadyConsumed
mülkütrue
ise isteği reddedin veya arayandan diğer kontrolleri geçmesini istemek gibi düzeltici bir işlem yapın.Ö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 jetonu tüketildi olarak işaretler. Aynı jetonda
verifyToken(appCheckToken, { consume: true })
'nin gelecekteki çağrıları,alreadyConsumed
değerinitrue
olarak ayarlar. (consume
ayarlanmamışsaverifyToken()
'ün, tüketilen bir jetonu reddetmediğini veya tüketilip tüketilmediğini bile kontrol etmediğini unutmayın.)
Belirli bir uç nokta için bu özelliği etkinleştirdiğinizde, uç noktayla birlikte kullanılacak sınırlı kullanıma yönelik jetonlar edinmek için uygulama istemci kodunuzu da güncellemeniz gerekir. Apple platformları, Android ve web için istemci tarafı dokümanları inceleyin.