什么可能使已注销的用户能够绕过 Firebase 默认存储规则并访问存储桶?

Posted

技术标签:

【中文标题】什么可能使已注销的用户能够绕过 Firebase 默认存储规则并访问存储桶?【英文标题】:What might enable a logged-out user to bypass Firebase default Storage rules and access a Storage bucket? 【发布时间】:2021-12-31 07:49:27 【问题描述】:

我一直在尝试使用 Firebase 代码在我的 Windows 11 电脑和我的 Firebase 存储桶之间上传/下载文件。一旦我得到它的工作,我意识到代码不包括登录。由于我使用的是默认 Cloud Storage 规则,因此我预计我的上传/下载调用会被退回。

rules_version = '2';
service firebase.storage 
  match /b/bucket/o 
    match /allPaths=** 
       allow read, write: if request.auth != null;
    
  

我清除了浏览器缓存并退出了 Google 和 Firebase 控制台,看看这是否解决了问题。它没有,也没有重新启动。但是当我发现代码在完全独立的机器上运行时出现了预期错误,我松了一口气。在这种情况下运行我的代码(现在部署到网络上)会产生预期的错误:

“糟糕 - 上传失败:错误 = FirebaseError:Firebase 存储:用户无权访问 'some-child'。(存储/未经授权)”。

但问题仍然存在于我的开发 PC 上,所以我的问题是,有什么可能将 Firebase 置于绕过云存储规则的状态,即使没有登录也允许存储桶访问?

这是我正在使用的 (firebase v9) 代码(它允许我将 PC 上的选定文件上传到存储桶中名为“some-child”的文件中,然后将其下载到名为 demo. txt 在我的下载文件夹中)。 :

import  initializeApp  from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-app.js';
import  getAuth, GoogleAuthProvider, signInWithPopup  from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-auth.js';
import  getStorage, ref, uploadBytes, getDownloadURL  from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-storage.js';

const firebaseConfig = 
    ...
;
const firebaseApp = initializeApp(firebaseConfig);

const provider = new GoogleAuthProvider();
const auth = getAuth();

const storage = getStorage();
const storageRef = ref(storage, 'some-child');

window.onload = function () 

    document.getElementById('fileitem').onchange = function ()  uploadFile() ;
    document.getElementById('downloadbutton').onclick = function ()  downloadFile() ;



function uploadFile() 
    var file = document.getElementById('fileitem').files[0];
    uploadBytes(storageRef, file)
        .then((snapshot) =>  
            alert('Successful  upload');
        )
        .catch((error) => 
            alert('Oops - upload failed : error = ' + error);
        );


function downloadFile() 

    var file = getDownloadURL(ref(storage, 'some-child'))
        .then((url) => 
            // `url` is the download URL for 'some-child' and can be downloaded directly:
            const xhr = new XMLHttpRequest();
            xhr.responseType = 'text';
            xhr.onload = (event) => 
                const blob = xhr.response;
                const a = document.getElementById('downloadanchor');
                a.href = window.URL.createObjectURL(new Blob([blob],  type: "text/plain" ));
                a.download = "demo.txt";
                a.click();
                alert('Successful download');
            ;
            xhr.open('GET', url);
            xhr.send();
        )
        .catch((error) => 
            alert('Oops - download failed : error = ' + error);
        );

当然有一个 html 前端。其内容如下:

    <input id="fileitem" type="file"><br></br>
    <button id="downloadbutton">Download</button>
    <a id="downloadanchor" href="" download></a>

【问题讨论】:

为了验证用户未登录,我建议您在尝试上传文件之前登录auth.currentUser.uid 有趣。在“问题项目”中,auth.currentUser.uid;报告为真实值。我为相同的源代码创建了另一个项目,这个项目说 auth.currentUser 为 null 并且出现了预期的错误。 【参考方案1】:

听起来您只登录了一个用户,但从未将其注销。 Firebase 保留用户凭据并在重新加载页面时恢复它们,然后将其与对数据库的调用一起发送。这通常正是您想要的,但在这里它似乎妨碍了您。

如果您不想使用身份验证,可以通过一次性调用 signOut 来sign the user out:

import  getAuth, ...  from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => 
  // Sign-out successful.
).catch((error) => 
  // An error happened.
);

【讨论】:

以上是关于什么可能使已注销的用户能够绕过 Firebase 默认存储规则并访问存储桶?的主要内容,如果未能解决你的问题,请参考以下文章

为啥从 firebase 控制台发送的通知能够绕过 android 后台任务限制? - 反应原生火力基地 -

用于 uid 列表的 Firebase 存储自定义元数据安全规则

Firebase 在创建新用户时注销当前用户

Firebase - 重新打开应用程序后用户注销时应用程序关闭

注销后清除 Firebase 持久性

如何在 Firebase 3.0 中注销用户?