保护 Google Firebase 免受 DDOS/攻击者的攻击并防止意外账单
Securing Google Firebase from DDOS / attackers and prevent surprise bills
我正在考虑使用 firebase 实时数据库,但我担心的有几件事:
- 高惊喜账单
- 系统故障
我正在考虑做几件事:
- 第 1 层:Firebase 前面的 CloudFare CDN。
- 第 2 层:安全规则,对写入/读取操作进行基于时间的速率限制。
- 第 3 层:只有经过良好身份验证的用户才能调用 firebase 端点。
- 应急层:我跟踪读写操作量。如果这些超过某个阈值,我将禁用我的项目的计费。
这足够安全吗?
如何保护我的 firebase 免受读/写攻击或 ddos 攻击?
对于大多数用例来说,写入漏洞利用通常相当容易防范;如果您只允许经过身份验证的(或管理员)写入,Firebase 安全规则应该涵盖您。
如果您有任何 public 用户无需身份验证即可访问的数据,读取会更具挑战性。
Google 云中的预算可以连接到 pub/sub 主题,因此一种选择是创建一个云功能,根据预算检查成本并在超过某个特定值时关闭计费帐户阈值。
Google 已为此 here 提供了示例。
围绕这三个步骤的一般方法是很好的做法。
请考虑 Firebase 是基于云的,因此它是世界的前沿和中心,这里有一些针对 Firebase 的具体建议以及如何引入看门狗实践:
Avoid insecure rules
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Look out for rule cascading ,确保遍历整棵树来检查规则
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid == $uid || root.child('users').child(auth.uid).child('isAdmin').val() == true",
".write": "root.child('users').child(auth.uid).child('isAdmin').val() == true",
".indexOn": ["email"]
}
}
}
}
像下面的代码一样,因为创建授权 允许创建恶意用户(可能由机器人)
恕我直言 - 我会制作这本手册,或者至少让它根据用户注册 IP 与蜜罐之类的东西进行检查
const getCustomClaimsByEmail = require('../utilities/get-custom-claims-by-email');
const setCustomClaims = require('../utilities/set-custom-claims');
module.exports = ({ admin, environment }) => user => {
const db = admin.firestore();
const usersCollection = db.collection(environment.schema.users);
const customClaimsRef = admin.database().ref(environment.schema.customClaims);
const auth = admin.auth();
const email = extractEmailFromUser(user);
return Promise.resolve()
.then(getCustomClaimsByEmail(customClaimsRef, email))
.then(setCustomClaims(auth, user.uid))
.then(claims => {
const update = mapUserUpdate(claims, user);
return usersCollection.doc(user.uid).set(update, { merge: true });
});
};
function mapUserUpdate(claims, user) {
const email = extractEmailFromUser(user);
return {
claims,
email,
emailVerified: user.emailVerified,
lastSignInTime: user.metadata.lastSignInTime,
creationTime: user.metadata.creationTime,
providerData: user.providerData,
};
}
function extractEmailFromUser(user) {
return user.email || user.providerData.find(({ email }) => email).email;
}
现在你的 DDOS/流量,
你可以avoid abusive traffic by following this checklist, and during launch follow these checklist.
我正在考虑使用 firebase 实时数据库,但我担心的有几件事:
- 高惊喜账单
- 系统故障
我正在考虑做几件事:
- 第 1 层:Firebase 前面的 CloudFare CDN。
- 第 2 层:安全规则,对写入/读取操作进行基于时间的速率限制。
- 第 3 层:只有经过良好身份验证的用户才能调用 firebase 端点。
- 应急层:我跟踪读写操作量。如果这些超过某个阈值,我将禁用我的项目的计费。
这足够安全吗?
如何保护我的 firebase 免受读/写攻击或 ddos 攻击?
对于大多数用例来说,写入漏洞利用通常相当容易防范;如果您只允许经过身份验证的(或管理员)写入,Firebase 安全规则应该涵盖您。
如果您有任何 public 用户无需身份验证即可访问的数据,读取会更具挑战性。
Google 云中的预算可以连接到 pub/sub 主题,因此一种选择是创建一个云功能,根据预算检查成本并在超过某个特定值时关闭计费帐户阈值。
Google 已为此 here 提供了示例。
围绕这三个步骤的一般方法是很好的做法。
请考虑 Firebase 是基于云的,因此它是世界的前沿和中心,这里有一些针对 Firebase 的具体建议以及如何引入看门狗实践:
Avoid insecure rules
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Look out for rule cascading ,确保遍历整棵树来检查规则
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid == $uid || root.child('users').child(auth.uid).child('isAdmin').val() == true",
".write": "root.child('users').child(auth.uid).child('isAdmin').val() == true",
".indexOn": ["email"]
}
}
}
}
像下面的代码一样,因为创建授权 允许创建恶意用户(可能由机器人)
恕我直言 - 我会制作这本手册,或者至少让它根据用户注册 IP 与蜜罐之类的东西进行检查
const getCustomClaimsByEmail = require('../utilities/get-custom-claims-by-email');
const setCustomClaims = require('../utilities/set-custom-claims');
module.exports = ({ admin, environment }) => user => {
const db = admin.firestore();
const usersCollection = db.collection(environment.schema.users);
const customClaimsRef = admin.database().ref(environment.schema.customClaims);
const auth = admin.auth();
const email = extractEmailFromUser(user);
return Promise.resolve()
.then(getCustomClaimsByEmail(customClaimsRef, email))
.then(setCustomClaims(auth, user.uid))
.then(claims => {
const update = mapUserUpdate(claims, user);
return usersCollection.doc(user.uid).set(update, { merge: true });
});
};
function mapUserUpdate(claims, user) {
const email = extractEmailFromUser(user);
return {
claims,
email,
emailVerified: user.emailVerified,
lastSignInTime: user.metadata.lastSignInTime,
creationTime: user.metadata.creationTime,
providerData: user.providerData,
};
}
function extractEmailFromUser(user) {
return user.email || user.providerData.find(({ email }) => email).email;
}