Firebase 安全核对清单

为了确保您的 Firebase 资源和用户数据安全无虞,请遵循以下准则。您不一定需要遵循每一项要求,但在开发应用时请牢记在心。

避免滥用性流量

为后端服务设置监控和提醒机制

如需检测拒绝服务攻击 (DOS) 等滥用性流量,请为 Cloud FirestoreRealtime DatabaseCloud StorageHosting 设置监控和提醒机制

如果您怀疑自己的应用受到攻击,请尽快与支持团队联系,告知他们发生了什么情况。

启用 App Check

为确保只有您的应用可以访问您的后端服务,请为支持 App Check 的每项服务启用该功能。

配置 Cloud Functions 函数以根据正常流量情况进行扩缩

Cloud Functions 函数会自动弹性扩缩以满足应用的需求,但是如果应用受到攻击,这可能意味着会产生巨额费用。为防止发生这种情况,您可以根据应用的正常流量情况来限制函数的并发实例数

设置提醒以便在快达到限制时收到通知

如果您的服务出现流量高峰,通常就会触发配额,并自动限制流向应用的流量。请务必监控您的用量和结算信息中心。您也可以对项目设置预算提醒,以便在资源用量将要超出预期时收到通知。

防止自我 DOS 攻击:使用模拟器在本地测试函数

开发 Cloud Functions 函数时,很容易不小心自己导致 DOS 攻击,例如创建无限的触发器写入循环。为了防止这些错误影响实际服务,您可以使用 Firebase Emulator Suite 进行开发。

(如果您不小心自己触发了 DOS,请取消部署您的函数,只需将其从 index.js 中移除,然后运行 firebase deploy --only functions 即可。)

在实时响应速度不太重要的场合,以防御性方式设计函数结构

如果您不需要实时给出函数的结果,则可以通过批量处理结果来降低滥用性流量的风险:将结果发布到 Pub/Sub 主题,然后使用预定函数定期处理结果。

了解 API 密钥

Firebase 服务的 API 密钥不是机密信息

Firebase 使用 API 密钥仅仅是为了向 Firebase 服务标识应用的 Firebase 项目,而不将其用于控制对数据库或 Cloud Storage 数据的访问权限(权限控制是使用 Firebase 安全规则实现的)。因此,您无需将 Firebase 服务的 API 密钥视为机密,可以放心地将其嵌入客户端代码中。详细了解 Firebase 的 API 密钥

设置 API 密钥范围

您可以创建范围限定为您的应用客户端的 API 密钥,将其作为一种额外防范机制来应对那些试图使用您的 API 密钥仿冒请求的攻击者。

确保 FCM 服务器密钥的机密性

与 Firebase 服务的 API 密钥不同,FCM 服务器密钥(由旧版 FCM HTTP API 使用)是敏感信息,必须确保其机密性。

确保服务账号密钥的机密性

与 Firebase 服务的 API 密钥不同,服务账号私钥(由 Admin SDK 使用)是敏感信息,必须确保其机密性。

安全规则

以生产模式或锁定模式初始化规则

设置 Cloud Firestore、Realtime Database 和 Cloud Storage 时,请将安全规则初始化为默认情况下拒绝所有访问,并在开发应用时添加规则,授予对特定资源的访问权限。

这是 Cloud Firestore(生产模式)和 Realtime Database(锁定模式)新实例的一项默认设置。设置新的数据库实例时,请选择此选项。

对于 Cloud Storage,开始时请先使用如下的安全规则配置:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

安全规则是一个架构;在添加文档时添加规则

请勿在应用开发完毕后再编写安全规则,把它视为一项在临近应用发布前才处理的事项。相反,应在开发应用的过程中编写安全规则,将它们视为数据库架构:每当需要使用新的文档类型或路径结构时,请首先编写其安全规则。

使用 Emulator Suite 对安全规则进行单元测试;将测试添加到 CI

为了确保您的安全规则与应用的开发保持一致,请使用 Firebase Emulator Suite 对规则进行单元测试,并将这些测试添加到持续集成 (CI) 流水线中。请参阅针对 Cloud FirestoreRealtime Database 的指南。

身份验证

自定义身份验证:在受信任(服务器端)的环境中创建 JWT

如果您已经拥有安全的登录系统(无论是自定义系统还是第三方服务),则可以使用现有系统向 Firebase 服务进行身份验证。在受信任的环境中创建自定义 JWT,然后将这些令牌传递给客户端,客户端会使用令牌进行身份验证(iOS+AndroidWebUnityC++)。

如需查看将自定义身份验证与第三方提供方结合使用的示例,请参阅博文使用 Okta 进行 Firebase 身份验证

代管式身份验证:OAuth 2.0 提供方最安全

如果您使用 Firebase 的代管式身份验证功能,OAuth 2.0/OpenID Connect 提供方方案(Google、Facebook 等)是最安全的。如果可以,您应该为这些提供方提供支持(具体取决于您的用户群)。

电子邮件密码身份验证:为登录端点设置较少的配额,以防止暴力破解攻击

如果您使用 Firebase 的代管式电子邮件密码身份验证服务,请减少 identitytoolkit.googleapis.com 端点的默认配额,以防止暴力破解攻击。您可以在 Google Cloud 控制台的 API 页面中执行此操作。

电子邮件密码身份验证:启用电子邮件枚举保护

如果您使用 Firebase 的代管式电子邮件密码身份验证服务,请启用电子邮件枚举保护,以防恶意操作者滥用项目的身份验证端点来猜测账号名称。

升级为 Cloud Identity Platform 以进行多重身份验证

为了提高登录安全性,您可以升级为 Cloud Identity Platform 来添加多重身份验证支持。升级后,您可以继续使用现有的 Firebase Authentication 代码。

匿名身份验证

仅将匿名身份验证用于热初始配置

在用户实际登录之前,仅使用匿名身份验证保存其基本状态。匿名身份验证不能替代用户登录。

如果用户在丢失手机后需要获取数据,可以让他们改用另一种登录方式

如果用户清空本地存储设备或切换设备,匿名身份验证数据将不会保留。在单一设备上,如果您需要在应用重启后仍保留数据,请让用户改为使用永久账号

使用安全规则,要求用户改为使用登录服务提供方或验证其电子邮件地址

任何人都可以在您的项目中创建一个匿名账号。考虑到这一点,请使用要求采用特定登录方法或经过验证的电子邮件地址的安全规则来保护所有非公开数据。

例如:

allow write: if request.auth.token.firebase.sign_in_provider != "anonymous";
allow write: if request.auth.token.email_verified = true;

环境管理

设置开发和预演项目

为开发、预演和生产环境设置单独的 Firebase 项目。 在对预演项目进行测试之前,请勿将客户端代码合并到生产环境中。

限制团队访问生产数据

如果您与较大规模的团队一起工作,则可以使用预定义角色或自定义 IAM 角色来限制对生产数据的访问,从而缓解错误和违规风险。

如果您的团队使用 Emulator Suite 进行开发,则可能不需要授予对生产项目的更广泛的访问权限。

库管理

当心拼错库名称或警惕新维护者

将库添加到项目中时,请特别注意库的名称及其维护者。与您要安装的库名称类似的库可能包含恶意代码。

请勿在不了解更改的情况下更新库

在升级之前,请查看您使用的所有库的更改日志。确保升级会提升价值,并检查维护者是否仍是您信任的一方。

将监控定时器库安装为开发或测试依赖项

使用 Snyk 之类的库扫描项目中是否存在不安全的依赖项。

为 Functions 设置监控;在库更新后对其进行检查

如果您使用 Cloud Functions logger SDK,则可以针对异常行为(包括由库更新引起的行为)进行监控并在发生时收到提醒

Cloud Functions 函数安全性

切勿将敏感信息存到 Cloud Functions 函数的环境变量中

在自托管的 Node.js 应用中,您通常会使用环境变量来包含私钥等敏感信息。请勿在 Cloud Functions 函数中执行这样的操作。Cloud Functions 会在函数调用之间重复使用环境,因此不应将敏感信息存储在环境中。

  • 如需存储 Firebase API 密钥(并非机密),只需将其嵌入到代码中。
  • 如果您在 Cloud Functions 函数中使用 Firebase Admin SDK,则无需明确提供服务账号凭据,因为 SDK 可以在初始化期间自动获取这些凭据。
  • 如果您要调用需要服务账号凭据的 Google 和 Google Cloud API,则 Node.js 的 Google Auth 库可以从应用默认凭据中获取这些凭据,然后自动将其填充到 Cloud Functions 函数中。
  • 如需将非 Google 服务的私钥和凭据提供给您的 Cloud Functions 函数,请使用 Cloud Secret Manager

加密敏感信息

如果您无法避免将敏感信息传递给 Cloud Functions 函数,则必须制订自己的自定义解决方案来对此类信息进行加密。

简单的函数更安全;如果您需要使用复杂函数,请考虑使用 Cloud Run

尽量使您的 Cloud Functions 函数尽可能简单易懂。函数的复杂性通常会导致难以发现的错误或意外行为。

如果您确实需要复杂的逻辑或环境配置,请考虑使用 Cloud Run,而不是 Cloud Functions。