Bạn có thể bảo vệ các tài nguyên không phải Firebase của ứng dụng, chẳng hạn như các chương trình phụ trợ tự lưu trữ, bằng Kiểm tra ứng dụng. Để làm như vậy, bạn sẽ cần phải thực hiện cả hai điều sau:
- Sửa đổi ứng dụng khách của bạn để gửi mã thông báo Kiểm tra ứng dụng cùng với từng yêu cầu tới chương trình phụ trợ của bạn, như được mô tả trên các trang dành cho iOS+ , Android và web .
- Sửa đổi chương trình phụ trợ của bạn để yêu cầu mã thông báo Kiểm tra ứng dụng hợp lệ với mọi yêu cầu, như được mô tả trên trang này.
xác minh mã thông báo
Để xác minh mã thông báo Kiểm tra ứng dụng trên chương trình phụ trợ của bạn, hãy thêm logic vào các điểm cuối API để thực hiện như sau:
Kiểm tra xem mỗi yêu cầu có bao gồm mã thông báo Kiểm tra ứng dụng hay không.
Xác minh mã thông báo Kiểm tra ứng dụng bằng SDK quản trị.
Nếu xác minh thành công, SDK quản trị sẽ trả về mã thông báo Kiểm tra ứng dụng đã giải mã. Xác minh thành công cho biết mã thông báo bắt nguồn từ một ứng dụng thuộc dự án Firebase của bạn.
Từ chối mọi yêu cầu không kiểm tra được. Ví dụ:
Node.js
Nếu bạn chưa cài đặt SDK quản trị Node.js , hãy cài đặt.
Sau đó, sử dụng phần mềm trung gian Express.js làm ví dụ:
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.
});
con trăn
Nếu bạn chưa cài đặt SDK quản trị Python , hãy cài đặt.
Sau đó, trong trình xử lý điểm cuối API của bạn, hãy gọi app_check.verify_token()
và từ chối yêu cầu nếu không thành công. Trong ví dụ sau, một hàm được trang trí bằng @before_request
thực hiện tác vụ này cho tất cả các yêu cầu:
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.
...
Đi
Nếu bạn chưa cài đặt SDK quản trị cho Go , hãy cài đặt.
Sau đó, trong trình xử lý điểm cuối API của bạn, hãy gọi appcheck.Client.VerifyToken()
và từ chối yêu cầu nếu không thành công. Trong ví dụ sau, hàm trình bao bọc thêm logic này vào trình xử lý điểm cuối:
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.
}
Khác
Nếu chương trình phụ trợ của bạn được viết bằng ngôn ngữ khác, thì bạn có thể sử dụng thư viện JWT có mục đích chung, chẳng hạn như thư viện được tìm thấy tại jwt.io , để xác minh mã thông báo Kiểm tra ứng dụng.
Logic xác minh mã thông báo của bạn phải hoàn thành các bước sau:
- Lấy Khóa web JSON công khai Kiểm tra ứng dụng Firebase (JWK) được đặt từ điểm cuối JWKS Kiểm tra ứng dụng:
https://firebaseappcheck.googleapis.com/v1/jwks
- Xác minh chữ ký của mã thông báo Kiểm tra ứng dụng để đảm bảo nó hợp lệ.
- Đảm bảo rằng tiêu đề của mã thông báo sử dụng thuật toán RS256.
- Đảm bảo rằng tiêu đề của mã thông báo có loại JWT.
- Đảm bảo rằng mã thông báo được phát hành bởi Kiểm tra ứng dụng Firebase trong dự án của bạn.
- Đảm bảo rằng mã thông báo chưa hết hạn.
- Đảm bảo rằng đối tượng của mã thông báo phù hợp với dự án của bạn.
- Tùy chọn : Kiểm tra xem chủ đề của mã thông báo có khớp với ID ứng dụng của ứng dụng của bạn không.
Khả năng của các thư viện JWT có thể khác nhau; đảm bảo hoàn thành thủ công bất kỳ bước nào không được thư viện bạn chọn xử lý.
Ví dụ sau đây thực hiện các bước cần thiết trong Ruby bằng cách sử dụng đá quý jwt
làm lớp phần mềm trung gian 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
Bảo vệ phát lại (beta)
Để bảo vệ điểm cuối khỏi các cuộc tấn công lặp lại, bạn có thể sử dụng mã thông báo Kiểm tra ứng dụng sau khi xác minh để chỉ có thể sử dụng mã này một lần.
Việc sử dụng tính năng bảo vệ phát lại sẽ thêm một chuyến đi khứ hồi mạng vào lệnh gọi verifyToken()
và do đó, thêm độ trễ cho bất kỳ điểm cuối nào sử dụng nó. Vì lý do này, chúng tôi khuyên bạn chỉ nên bật tính năng bảo vệ phát lại trên các điểm cuối đặc biệt nhạy cảm.
Để sử dụng bảo vệ phát lại, hãy làm như sau:
Trong Bảng điều khiển đám mây , hãy cấp vai trò "Trình xác minh mã thông báo kiểm tra ứng dụng Firebase" cho tài khoản dịch vụ được sử dụng để xác minh mã thông báo.
- Nếu bạn đã khởi chạy SDK quản trị bằng thông tin đăng nhập tài khoản dịch vụ SDK quản trị mà bạn đã tải xuống từ bảng điều khiển Firebase, thì vai trò bắt buộc đã được cấp.
- Nếu bạn đang sử dụng Chức năng đám mây thế hệ thứ nhất với cấu hình SDK quản trị mặc định, hãy cấp vai trò cho tài khoản dịch vụ mặc định của App Engine . Xem Thay đổi quyền đối với tài khoản dịch vụ .
- Nếu bạn đang sử dụng Chức năng đám mây thế hệ thứ 2 với cấu hình SDK quản trị mặc định, hãy cấp vai trò cho tài khoản dịch vụ điện toán mặc định .
Sau đó, để sử dụng mã thông báo, hãy chuyển
{ consume: true }
cho phương thứcverifyToken()
và kiểm tra đối tượng kết quả; nếu thuộc tínhalreadyConsumed
làtrue
, hãy từ chối yêu cầu hoặc thực hiện một số hành động khắc phục, chẳng hạn như yêu cầu người gọi vượt qua các bước kiểm tra khác.Ví dụ:
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.
Điều này xác minh mã thông báo và sau đó đánh dấu nó là đã sử dụng. Các lệnh gọi
verifyToken(appCheckToken, { consume: true })
trong tương lai trên cùng một mã thông báo sẽ được đặtalreadyConsumed
thànhtrue
. (Lưu ý rằngverifyToken()
không từ chối mã thông báo đã sử dụng hoặc thậm chí kiểm tra xem nó có được sử dụng hay không nếuconsume
không được đặt.)
Khi bật tính năng này cho một điểm cuối cụ thể, bạn cũng phải cập nhật mã ứng dụng khách của mình để nhận mã thông báo sử dụng có giới hạn có thể tiêu hao để sử dụng với điểm cuối. Xem tài liệu phía máy khách cho nền tảng Apple , Android và web .