【问题标题】:Firebase callable cloud functions security & CORSFirebase 可调用云功能安全性和 CORS
【发布时间】:2021-06-07 05:58:14
【问题描述】:

我正在尝试在我的 firebase 应用程序中实现一个可调用的云功能,它将秘密存储到秘密管理器存储桶中。

我知道一旦用户登录,可调用函数就可以从会话中访问 auth.uid,并且我可以在函数内实现验证,但我仍然想知道如何保护函数的公共端点因为我可以看到,如果我只是尝试访问函数 URL,它实际上会计入云调用配额,即使它返回错误也是如此。

我尝试在函数设置中禁用 allUsers 调用权限,这实际上使 url 无法访问,但同时在尝试从我的应用程序调用函数时出现此错误 -

CORS 政策已阻止从源“https://atlaspark-app.web.app”访问“https://europe-west1-atlaspark-app.cloudfunctions.net/{cloudFunctionName}”获取:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

对可能导致此问题的任何建议?

【问题讨论】:

    标签: firebase google-cloud-functions


    【解决方案1】:

    您正在使用 Firebase HTTPS Callable Functions,它具有 Firebase 身份验证 的功能来对您的应用的用户进行身份验证。

    但您希望将 Cloud Function 设为私有以确保安全且不被公开访问。

    =======编辑=======

    • 为什么在将您的 Cloud Function 设为私有后无法访问您的 URL?

      由于 Cloud Function 是私有的,因此需要 Authentication 才能访问。您将无法从浏览器访问 Cloud Function 端点,因为它需要与有权调用 Cloud Function 的 IAM 用户或服务账户相关的授权令牌。并且浏览器不会自动提供授权令牌。

    • 您在客户端遇到了 CORS 问题。

      我通过创建 私有云函数(通过从 Cloud Function Invoker Role 中删除 AllUsers 成员)并从 Firebase 应用程序调用它来重现该问题。我确实遇到了 CORS 问题。

    为了避免 CORS,我尝试在 firebase.jon 中添加 Cloud 功能作为 Firebase Hosting 重写:

    注意:Firebase Hosting 仅支持 us-central1 中的 Cloud Functions,因此此选项不适合您。但是,我在 us-central1 中使用 Firebase Hosting 进行了以下测试

    "rewrites": [
    
    {
    "source":"/test",
    "function":"test"
    }
    ]
    

    另外,我更改了云函数代码以验证ID tokens

    云功能

    const cors = require('cors')({origin: true});
    const functions = require('firebase-functions');
    
    var admin = require("firebase-admin");
    
    var serviceAccount = require(".ServiceAccount.json");
    
    admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "DATABASE_URL"
    });
    
    exports.test = functions.https.onRequest((req, res) => {
       cors(req, res, () => {
       const tokenId = req.get('Authorization').split('Bearer ')[1];
    
       return admin.auth().verifyIdToken(tokenId)
          .then((decoded) => res.status(200).send(decoded))
          .catch(function(err) {
               console.error(err);
               console.log(err);
               res.status(401).send(err)});
          });
    });
    
    

    客户端

    firebase.auth().currentUser.getIdToken(true)
    .then(function(idToken){
        console.log('Id token is..');
        console.log(idToken);
    
        fetch('Cloud_Function_endpoint',{
            headers: {
              'Content-Type': 'application/json',
              'Authorization': 'Bearer ' + idToken
            },
            method: 'post',
            body: JSON.stringify({ data })
        }).then(result => {
           console.log(result);
        }).catch(error => {
           console.log(error);
       });
    }).catch(function(error){
        console.log(error);
    });
    
    

    因此,在进行这些更改后,我不再遇到 CORS 问题,而是收到 401 (Unauthorized) 错误。

    经过测试的解决方案:

    • 我们不能使用 Firebase 托管,因为请求来自客户端,因此没有 Firebase 托管服务帐户可以添加角色/权限。

    • 要保护云功能,另一种方法是启用Domain Restriction Sharing Policy (DRS),这样我们将无法为公共云功能提供服务。

    • 但前一个与从云函数中删除 AllUsers 使其私有化相同。

    • 我发现对于私有函数,我们可以为给定的用户/服务帐户指定 IAM 策略。为了验证来自客户端的请求,我们需要提供与the user / service account 相关联的不记名令牌。但这也无法实现,因为 IAM 所需的不记名令牌寿命太短,无法在 firebase 中使用.json 文件。

    结论:

    • 无法从 Firebase 应用访问私有云函数。
    • 唯一的解决方案是拥有一个公共云功能。

    【讨论】:

    • 嘿,感谢您的回复,但正如我在帖子中提到的那样,当我在我的 IAM 设置中删除 allUsers Invoker 权限从而尝试使用 http只有我的应用的用户可以访问触发端点。
    • 哦,我明白了,您能否分享您的代码以查看可能导致这些错误的原因?之后我会更新答案。
    • 例如一个基本的测试函数:const functions = require("firebase-functions"); exports.test = functions .region("europe-west2") .https.onCall((data, context) => { try { return { success: true }; } catch (e) { throw new functions.https.HttpsError("unknown"); } }); 然后我在我的前端组件中调用它:firebase.app().functions('europe-west2').httpsCallable('test')
    • 带有可调用函数的控制台中的 CORS 错误仅表示 Cloud Function 中存在错误。您能否检查 Firebase 控制台内的日志并查看实际错误? CORS 不适用于可调用函数,因为它们是自动添加的。
    • 不幸的是,情况并非如此。仅当我转到 IAM 并撤销给定函数的 allUsers 函数调用者权限时,该函数才会引发此错误。如果我将此角色重新应用于 IAM,该功能将再次起作用。
    猜你喜欢
    • 1970-01-01
    • 2019-03-22
    • 2018-08-27
    • 2021-04-08
    • 2021-03-05
    • 2018-05-15
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    相关资源
    最近更新 更多