如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点?

Posted

技术标签:

【中文标题】如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点?【英文标题】:How to protect firebase Cloud Function HTTP endpoint using authenticated id token and database rules? 【发布时间】:2018-07-12 13:03:51 【问题描述】:
admin.auth().verifyIdToken(tokenId)
      .then((decoded) => res.status(200).send(decoded))

我了解verifyIdToken() 可以验证来自 Firebase 身份验证客户端的用户 ID 令牌。但是,我们需要通过确保数据库查询受到为令牌中标识的用户定义的数据库安全规则的限制来保护我们的云功能。鉴于默认情况下 admin SDK 具有无限访问权限,我如何将其访问权限限制为仅经过身份验证的用户的访问权限?

【问题讨论】:

您能否编辑您的问题以解释“保护”功能的含义?这有点模糊。 我们要确保我们的http trigger api端点的数据库读/写访问遵循firebase中的database-rules.json。 我们的第一次尝试是在我们的 http 触发器 API 中的一些 get/update/set/remove 访问中使用 firebase web(使用令牌登录)而不是 firebase admin。它有效,但不可扩展。 我很想知道什么是不可扩展的? (这绝对不是最好的解决方案,但你在测量什么?) ` const firebase = require('firebase'); const userGet = (validFirebasePath) => firebaseDatabase .database() .ref(validFirebasePath) .once('value') .then(snapshot => snapshot.val()); export.apiHandler = (request, response) => // 我们从请求中获取 accessToken getCustomToken(accessToken) .then((customToken) => firebase.auth().signInWithCustomToken(customToken) .then(() => userGet ('users/userA')) .then(data => response.json(data)) ; ` 这是我们的第一次尝试。 【参考方案1】:

看看下面的HTTPS函数。它执行以下任务:

    使用 Admin SDK 验证 Firebase 身份验证 ID 令牌。令牌来自查询字符串(但您应该use a better solution 来传输令牌)。 从解码后的令牌中提取用户的 UID。 制作默认 Firebase 初始化配置对象的副本,然后使用 UID 将名为 databaseAuthVariableOverride 的属性添加到 limit the privileges of the caller。 使用新选项初始化 App 对象(名为“用户”)的新非默认实例。这个App object 现在可用于访问数据库,同时遵守为该用户制定的安全规则。 Admin SDK 与userApp 一起用于对某个保护路径进行数据库查询。 如果查询成功,请记住要发送给客户端的响应。 如果查询因安全原因而失败,请记住要发送给客户端的错误响应。 清理此 Admin SDK 实例。此代码采取一切预防措施以确保在任何情况下都调用userApp.delete()不要忘记这样做,否则会随着更多用户访问此功能而导致内存泄漏。 实际发送响应。这将终止函数。

这是一个工作函数:

const admin = require("firebase-admin")
admin.initializeApp()

exports.authorizedFetch = functions.https.onRequest((req, res) => 
    let userApp
    let response
    let isError = false

    const token = req.query['token']

    admin.auth().verifyIdToken(token)
    .then(decoded => 
        // Initialize a new instance of App using the Admin SDK, with limited access by the UID
        const uid = decoded.uid
        const options = Object.assign(, functions.config().firebase)
        options.databaseAuthVariableOverride =  uid 
        userApp = admin.initializeApp(options, 'user')
        // Query the database with the new userApp configuration
        return admin.database(userApp).ref("/some/protected/path").once('value')
    )
    .then(snapshot => 
        // Database fetch was successful, return the user data
        response = snapshot.val()
        return null
    )
    .catch(error => 
        // Database fetch failed due to security rules, return an error
        console.error('error', error)
        isError = true
        response = error
        return null
    )
    .then(() => 
        // This is important to clean up, returns a promise
        if (userApp) 
            return userApp.delete()
        
        else 
            return null
        
    )
    .then(() => 
        // send the final response
        if (isError) 
            res.status(500)
        
        res.send(response)
    )
    .catch(error => 
        console.error('final error', error)
    )
)

再次注意,在任何情况下都应调用userApp.delete(),以避免泄漏 App.如果您的想法是根据用户为每个新应用程序赋予一个唯一的名称,这不是一个好主意,因为当新用户继续访问此功能时,您仍然可能会耗尽内存。为了安全起见,每次调用都要清理它。

还要注意,userApp.delete() 应该在在发送响应之前被调用,因为发送响应会终止函数,并且您不希望清理因任何原因而中断。 p>

【讨论】:

你能帮忙吗,如果有人可以拦截对 firebase 的调用并获取身份服务 API 完成的 ID 令牌请求,然后使用该 ID 令牌访问所有 https 调用并修改内容。在使用带有 Firebase 的 ios/android 应用程序时,可以做些什么来防止中间人攻击或保护云功能。 这是否需要云功能上 allUsers 的调用角色?

以上是关于如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不经过注册用户身份验证的情况下保护公共API请求

如何使用基于 JWT 令牌的 express 获取经过身份验证的用户信息

使用 jwt 身份验证保护反应应用程序

使用jwt身份验证保护react应用程序

如何使用 Vuejs 和 Laravel 获取当前经过身份验证的用户 ID?

是否可以使用 id 令牌进行电子邮件身份验证?