يمكنك حماية موارد تطبيقك بخلاف Firebase ، مثل الخلفيات المستضافة ذاتيًا ، باستخدام App Check. للقيام بذلك ، سوف تحتاج إلى القيام بالأمرين التاليين:
- قم بتعديل عميل التطبيق الخاص بك لإرسال رمز التحقق من التطبيق جنبًا إلى جنب مع كل طلب إلى الواجهة الخلفية ، كما هو موضح في صفحات iOS + و Android والويب .
- قم بتعديل الواجهة الخلفية للمطالبة برمز مميز صالح للتحقق من التطبيق مع كل طلب ، كما هو موضح في هذه الصفحة.
التحقق من الرمز
للتحقق من الرموز المميزة للتحقق من التطبيق على الواجهة الخلفية ، أضف منطقًا إلى نقاط نهاية واجهة برمجة التطبيقات التي تقوم بما يلي:
تحقق من أن كل طلب يتضمن رمز التحقق من التطبيق.
تحقق من رمز التحقق من التطبيق باستخدام Admin SDK.
إذا نجح التحقق ، فإن Admin SDK تُرجع الرمز المميز للتحقق من التطبيق الذي تم فك ترميزه. يشير التحقق الناجح إلى أن الرمز المميز نشأ من تطبيق ينتمي إلى مشروع Firebase الخاص بك.
رفض أي طلب يفشل أي من الشيكات. على سبيل المثال:
Node.js
إذا لم تكن قد قمت بالفعل بتثبيت Node.js Admin SDK ، فقم بذلك.
ثم ، باستخدام البرنامج الوسيط Express.js كمثال:
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 Admin SDK ، فقم بذلك.
بعد ذلك ، في معالجات نقطة نهاية API الخاصة بك ، اتصل بـ app_check.verify_token()
ورفض الطلب إذا فشل. في المثال التالي ، تقوم دالة مزينة بـ @before_request
بتنفيذ هذه المهمة لجميع الطلبات:
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.
...
يذهب
إذا لم تكن قد قمت بالفعل بتثبيت Admin SDK for Go ، فقم بذلك.
ثم ، في معالجات نقطة نهاية API ، اتصل بـ appcheck.Client.VerifyToken()
ورفض الطلب إذا فشل. في المثال التالي ، تضيف دالة المجمع هذا المنطق إلى معالجات نقطة النهاية:
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.
}
آخر
إذا كانت الواجهة الخلفية الخاصة بك مكتوبة بلغة أخرى ، فيمكنك استخدام مكتبة JWT للأغراض العامة ، مثل تلك الموجودة في jwt.io ، للتحقق من رموز التحقق من التطبيق.
يجب أن يكمل منطق التحقق من الرمز المميز الخطوات التالية:
- احصل على Firebase App Check العام JSON Web Key (JWK) المعين من نقطة نهاية JWKS App Check:
https://firebaseappcheck.googleapis.com/v1/jwks
- تحقق من توقيع رمز التحقق من التطبيق للتأكد من شرعيته.
- تأكد من أن رأس الرمز المميز يستخدم الخوارزمية RS256.
- تأكد من أن رأس الرمز المميز من نوع JWT.
- تأكد من إصدار الرمز المميز بواسطة Firebase App Check ضمن مشروعك.
- تأكد من عدم انتهاء صلاحية الرمز المميز.
- تأكد من تطابق جمهور الرمز المميز مع مشروعك.
- اختياري : تحقق من تطابق موضوع الرمز المميز مع معرف التطبيق للتطبيق.
يمكن أن تختلف إمكانيات مكتبات JWT ؛ تأكد من إكمال أي خطوات لا تتعامل معها المكتبة التي تختارها يدويًا.
يقوم المثال التالي بتنفيذ الخطوات الضرورية في Ruby باستخدام jwt
gem كطبقة Rack وسيطة.
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
إعادة الحماية (تجريبي)
لحماية نقطة نهاية من هجمات إعادة التشغيل ، يمكنك استخدام رمز التحقق من التطبيق بعد التحقق منه بحيث يمكن استخدامه مرة واحدة فقط.
يؤدي استخدام حماية إعادة التشغيل إلى إضافة رحلة ذهابًا وإيابًا عبر الشبكة إلى مكالمة verifyToken()
، وبالتالي يضيف زمن انتقال إلى أي نقطة نهاية تستخدمه. لهذا السبب ، نوصي بتمكين حماية إعادة التشغيل فقط على نقاط النهاية الحساسة بشكل خاص.
لاستخدام الحماية من إعادة التشغيل ، تأكد أولاً من تمكين دور IAM "Firebase App Check Token Verifier" لحساب الخدمة الذي تستخدمه مع Admin SDK. في وظائف السحابة ، عادة ما يكون هذا هو حساب خدمة الحساب الافتراضي ؛ على الأنظمة الأساسية الأخرى ، يكون هذا عادةً حساب خدمة Admin SDK. يمكنك تمكين أدوار IAM في وحدة التحكم السحابية .
بعد ذلك ، لاستهلاك رمز مميز ، مرر { consume: true }
إلى طريقة verifyToken()
وفحص الكائن الناتج ؛ إذا كانت الخاصية alreadyConsumed
true
، فقم برفض الطلب أو اتخذ نوعًا من الإجراءات التصحيحية ، مثل مطالبة المتصل باجتياز عمليات التحقق الأخرى.
على سبيل المثال:
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.
سيؤدي هذا إلى التحقق من الرمز المميز ثم وضع علامة عليه كمستهلك. سيتم تعيين الاستدعاءات المستقبلية لـ verifyToken(appCheckToken, { consume: true })
على نفس الرمز المميز alreadyConsumed
إلى true
. (لاحظ أن verifyToken()
لن يرفض رمزًا مستهلكًا أو حتى يتحقق مما إذا كان مستهلكًا إذا لم يتم تعيين consume
.)
عند تمكين هذه الميزة لنقطة نهاية معينة ، يجب عليك أيضًا تحديث رمز عميل التطبيق الخاص بك للحصول على الرموز المميزة القابلة للاستهلاك ذات الاستخدام المحدود للاستخدام مع نقطة النهاية. راجع المستندات من جانب العميل لأنظمة Apple الأساسية و Android والويب .