Google/Firebase 云函数的速率限制?
Rate limiting for Google/Firebase cloud functions?
我正在使用 Firebase 开发一个在内部使用 Cloud Functions 作为 REST API 的应用程序。我的问题是,除了 per-IP 和 per-IP 和 每个用户 基础,而不是每个应用程序(因为它都是一个应用程序)。对小突发的可选支持也是可取的。
示例代码(参见 // TODO:
评论):
exports.myCoolFunction = functions.https.onRequest((req, res) => {
// TODO: implement IP rate-limiting here
unpackToken(req).then((token) => { // unpackToken resolves with a response similar to verifyIdToken based on the "Authorization" header contents
// TODO: implement user-based rate-limiting here (based on token.uid)
if (!req.body) return res.status(400).end();
if (typeof req.body.name !== "string") return res.status(400).end();
if (typeof req.body.user !== "string") return res.status(400).end();
// more input sanitization and function logic here
return res.status(501).end(); // fallback in all requests, do not remove
}).catch(() => res.status(403).end());
});
如果超过速率限制,我想简单地用 529 Too Many Requests
状态代码终止请求。这是为了防止应用程序错误充斥网络并防止滥用 REST API.
This should take into account Firebase spinning up/down server instances and having multiple instances running simultaneously.
I am also using a Firestore database and can use the legacy real-time database if necessary.
针对每个用户执行此操作听起来相当简单:
- 在每个请求中将用户的 ID 令牌传递给 Cloud Functions。
- 解码您的 Cloud Function 中的 ID 令牌以确定 UID。有关前两个步骤的示例,请参阅 the
functions-samples
repo.
- 将用户 UID 调用函数的事实推送到数据库,可能将其添加到列表中。例如。
admin.database().ref(`/userCalls/$uid`).push(ServerValue.TIMESTAMP)
.
- 查询最近通话次数,类似
admin.database().ref(`/userCalls/$uid`).orderByKey().startAt(Date.now()-60000)
.
- 统计结果,如果太高则拒绝。
我不确定调用方的 IP 地址是否已传递给 Cloud Functions。如果是,您可以对 IP 地址执行相同的逻辑。如果不通过,将很难以不易被欺骗的方式进行评分限制。
我制作了一个库来限制对 firebase 函数的调用:firebase-functions-rate-limiter 该库使用 realtimeDB 或 firestore(可配置)作为后端。它存储数据的方式与 Frank 描述的类似,但更经济。它不使用集合,而是使用每个限定符(例如用户 ID)的数组的单个文档。这意味着对于超出的调用只有一次读取,对于允许的调用只有一次读写。
$ npm i --save firebase-functions-rate-limiter
这是一个例子:
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { FirebaseFunctionsRateLimiter } from "firebase-functions-rate-limiter";
admin.initializeApp(functions.config().firebase);
const database = admin.database();
const limiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
{
name: "rate_limiter_collection",
maxCalls: 2,
periodSeconds: 15,
},
database,
);
exports.testRateLimiter =
functions.https.onRequest(async (req, res) => {
await limiter.rejectOnQuotaExceeded(); // will throw HttpsException with proper warning
res.send("Function called");
});
我正在使用 Firebase 开发一个在内部使用 Cloud Functions 作为 REST API 的应用程序。我的问题是,除了 per-IP 和 per-IP 和 每个用户 基础,而不是每个应用程序(因为它都是一个应用程序)。对小突发的可选支持也是可取的。
示例代码(参见 // TODO:
评论):
exports.myCoolFunction = functions.https.onRequest((req, res) => {
// TODO: implement IP rate-limiting here
unpackToken(req).then((token) => { // unpackToken resolves with a response similar to verifyIdToken based on the "Authorization" header contents
// TODO: implement user-based rate-limiting here (based on token.uid)
if (!req.body) return res.status(400).end();
if (typeof req.body.name !== "string") return res.status(400).end();
if (typeof req.body.user !== "string") return res.status(400).end();
// more input sanitization and function logic here
return res.status(501).end(); // fallback in all requests, do not remove
}).catch(() => res.status(403).end());
});
如果超过速率限制,我想简单地用 529 Too Many Requests
状态代码终止请求。这是为了防止应用程序错误充斥网络并防止滥用 REST API.
This should take into account Firebase spinning up/down server instances and having multiple instances running simultaneously.
I am also using a Firestore database and can use the legacy real-time database if necessary.
针对每个用户执行此操作听起来相当简单:
- 在每个请求中将用户的 ID 令牌传递给 Cloud Functions。
- 解码您的 Cloud Function 中的 ID 令牌以确定 UID。有关前两个步骤的示例,请参阅 the
functions-samples
repo. - 将用户 UID 调用函数的事实推送到数据库,可能将其添加到列表中。例如。
admin.database().ref(`/userCalls/$uid`).push(ServerValue.TIMESTAMP)
. - 查询最近通话次数,类似
admin.database().ref(`/userCalls/$uid`).orderByKey().startAt(Date.now()-60000)
. - 统计结果,如果太高则拒绝。
我不确定调用方的 IP 地址是否已传递给 Cloud Functions。如果是,您可以对 IP 地址执行相同的逻辑。如果不通过,将很难以不易被欺骗的方式进行评分限制。
我制作了一个库来限制对 firebase 函数的调用:firebase-functions-rate-limiter 该库使用 realtimeDB 或 firestore(可配置)作为后端。它存储数据的方式与 Frank 描述的类似,但更经济。它不使用集合,而是使用每个限定符(例如用户 ID)的数组的单个文档。这意味着对于超出的调用只有一次读取,对于允许的调用只有一次读写。
$ npm i --save firebase-functions-rate-limiter
这是一个例子:
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { FirebaseFunctionsRateLimiter } from "firebase-functions-rate-limiter";
admin.initializeApp(functions.config().firebase);
const database = admin.database();
const limiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
{
name: "rate_limiter_collection",
maxCalls: 2,
periodSeconds: 15,
},
database,
);
exports.testRateLimiter =
functions.https.onRequest(async (req, res) => {
await limiter.rejectOnQuotaExceeded(); // will throw HttpsException with proper warning
res.send("Function called");
});