App Check की मदद से, अपने ऐप्लिकेशन के ऐसे संसाधनों को सुरक्षित किया जा सकता है जो Firebase के नहीं हैं. जैसे, खुद के होस्ट किए गए बैकएंड. ऐसा करने के लिए, आपको ये दोनों काम करने होंगे:
- अपने ऐप्लिकेशन क्लाइंट में बदलाव करें, ताकि आपके बैकएंड को हर अनुरोध के साथ App Check टोकन भेजा जा सके. इस बारे में iOS+, Android, और वेब के पेजों पर बताया गया है.
- अपने बैकएंड में बदलाव करें, ताकि हर अनुरोध के साथ मान्य App Check टोकन की ज़रूरत पड़े. इसके बारे में इस पेज पर बताया गया है.
टोकन की पुष्टि करना
अपने बैकएंड पर App Check टोकन की पुष्टि करने के लिए, अपने एपीआई एंडपॉइंट में ऐसा लॉजिक जोड़ें जो ये काम करता हो:
देखें कि हर अनुरोध में App Check टोकन शामिल हो.
एडमिन SDK का इस्तेमाल करके, App Check टोकन की पुष्टि करें.
पुष्टि होने पर, एडमिन SDK टूल, डिकोड किया गया App Check टोकन दिखाता है. पुष्टि होने का मतलब है कि टोकन आपके 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
अगर आपने Python Admin SDK पहले से इंस्टॉल नहीं किया है, तो इसे इंस्टॉल करें.
इसके बाद, अपने एपीआई एंडपॉइंट हैंडलर में, 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.
...
शुरू करें
अगर आपने Go के लिए एडमिन SDK टूल को पहले से इंस्टॉल नहीं किया है, तो ऐसा करें.
इसके बाद, अपने एपीआई एंडपॉइंट हैंडलर में 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.
}
अन्य
अगर आपका बैकएंड किसी दूसरी भाषा में लिखा गया है, तो App Check टोक़न की पुष्टि करने के लिए, सामान्य तौर पर इस्तेमाल की जाने वाली JWT लाइब्रेरी का इस्तेमाल किया जा सकता है. जैसे, jwt.io पर मौजूद लाइब्रेरी.
आपके टोकन की पुष्टि करने वाले लॉजिक को ये चरण पूरे करने होंगे:
- AppCheck JWKS एंडपॉइंट से, Firebase ऐप्लिकेशन की जांच करने वाली सार्वजनिक JSON वेब कुंजी (JWK) सेट पाएं:
https://firebaseappcheck.googleapis.com/v1/jwks
- App Check टोकन के हस्ताक्षर की पुष्टि करके, पक्का करें कि वह मान्य है.
- पक्का करें कि टोकन के हेडर में RS256 एल्गोरिदम का इस्तेमाल किया गया हो.
- पक्का करें कि टोकन के हेडर का टाइप JWT हो.
- पक्का करें कि टोकन, आपके प्रोजेक्ट के तहत Firebase ऐप्लिकेशन जांच की सुविधा से जारी किया गया हो.
- पक्का करें कि टोकन की समयसीमा खत्म न हुई हो.
- पक्का करें कि टोकन की ऑडियंस आपके प्रोजेक्ट से मेल खाती हो.
- ज़रूरी नहीं: देखें कि टोकन का विषय, आपके ऐप्लिकेशन के ऐप्लिकेशन आईडी से मेल खाता हो.
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()
कॉल में नेटवर्क का राउंड ट्रिप जुड़ जाता है. इसलिए, इसका इस्तेमाल करने वाले किसी भी एंडपॉइंट में इंतज़ार का समय बढ़ जाता है. इसलिए, हमारा सुझाव है कि आप रिप्ले प्रोटेक्शन की सुविधा को सिर्फ़ खास तौर पर संवेदनशील एंडपॉइंट पर चालू करें.
फिर से चलाए जाने से रोकने की सुविधा का इस्तेमाल करने के लिए, यह तरीका अपनाएं:
Cloud Console में, टोकन की पुष्टि करने के लिए इस्तेमाल किए जाने वाले सेवा खाते को "Firebase ऐप्लिकेशन की जांच करने वाला टोकन पुष्टि करने वाला" रोल दें.
- अगर आपने Firebase कंसोल से डाउनलोड किए गए Admin SDK के सेवा खाते के क्रेडेंशियल का इस्तेमाल करके, Admin SDK को शुरू किया है, तो ज़रूरी भूमिका पहले से ही दी जा चुकी है.
- अगर डिफ़ॉल्ट एडमिन एसडीके कॉन्फ़िगरेशन के साथ, पहले जनरेशन के Cloud Functions का इस्तेमाल किया जा रहा है, तो App Engine के डिफ़ॉल्ट सेवा खाते को भूमिका दें. सेवा खाते की अनुमतियां बदलना लेख पढ़ें.
- अगर डिफ़ॉल्ट Admin SDK कॉन्फ़िगरेशन के साथ, दूसरे जनरेशन के Cloud Functions का इस्तेमाल किया जा रहा है, तो डिफ़ॉल्ट कंप्यूट सेवा खाते को भूमिका दें.
इसके बाद, टोकन का इस्तेमाल करने के लिए,
verifyToken()
के लिए{ consume: true }
को पास करें और नतीजे के ऑब्जेक्ट की जांच करें. अगर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, और वेब के लिए, क्लाइंट-साइड दस्तावेज़ देखें.