Firebase 存储安全规则和上传文件的下载令牌

Posted

技术标签:

【中文标题】Firebase 存储安全规则和上传文件的下载令牌【英文标题】:Firebase Storage security rules and download tokens for uploaded files 【发布时间】:2019-10-21 03:04:14 【问题描述】:

TLDR:这是关于从task.snapshot.ref.getDownloadURL() 及其各自的downloadToken 返回的URL 的问题。它询问token 的主要作用和功能是什么,以及对于将通过安全规则公开获得的文件是否有必要。


我刚刚在 https://firebase.google.com/docs/storage/web/upload-files 和此 Youtube tutorial from the Firebase official channel 上完成了有关将文件上传和下载到 Firebase 存储的教程指南。

我正在为我的一个 Firebase 网络应用程序(React + Firebase)中的博客部分构建一个内容管理系统。

我有一个组件可以让管理员选择一张图片并将其上传到 Firebase 存储桶以显示在特定的博客文章中。特定blogPost 的所有图像都应位于特定blog-post-slug 的文件夹内。

例子:

//bucket/some-blog-post-slug/image1.jpg

管理员在<input type='file'/> 上选择新文件时运行的代码:

function onFileSelect(e) 
  const file = e.target.files[0];
  const storageRef = firebase.storage().ref('some-slug/' + file.name);
  const task = storageRef.put(file);
  task.on('state_changed',
    function progress(snapshot) 
      setPercent((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
    ,
    function error(err) 
      console.log(err);
    ,
    function complete() 
      console.log('Upload complete!');
      task.snapshot.ref.getDownloadURL().then(function(downloadURL) 
        console.log('File available at', downloadURL);
        props.changeImageSrc(downloadURL);
      );
    
  );

上面的代码返回downloadURL,它将被保存到blogPost文档中的Firestore。

downloadURL 具有以下格式:

https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg?alt=media&token=TOKEN_VALUE

你可以看到它带有一个“基本网址”:https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg

并且 basicURL 附加了以下 GET 参数:

alt=mediatoken=TOKEN_VALUE

我不知道我会得到一个令牌,所以我现在正在测试它的行为以了解更多信息。


允许存储读取的行为:

service firebase.storage 
  match /b/bucket/o 
    match /allPaths=** 
      allow read, write;

当我访问 basicURL 时: 我收到一个对象以响应上传的文件详细信息:

  "name": "some-slug/FILE_NAME.jpg",
  "bucket": "MYBUCKET",
  "generation": "GENERATION_NUMBER",
  "metageneration": "1",
  "contentType": "image/jpeg",
  "timeCreated": "2019-06-05T13:53:57.070Z",
  "updated": "2019-06-05T13:53:57.070Z",
  "storageClass": "STANDARD",
  "size": "815155",
  "md5Hash": "Mj4aCPs21NUNxXpKg1bHirFIO0A==",
  "contentEncoding": "identity",
  "contentDisposition": "inline; filename*=utf-8''FILE_NAME.jpg",
  "crc32c": "zhkQMQ==",
  "etag": "CKu4a1+u2+0ucI412CEAE=",
  "downloadTokens": "TOKEN_VALUE"

当我访问 basicURL?alt=media

图像已显示。

当我访问 basicURL?alt=media&token=TOKEN_VALUE

图像已显示。

存储读取受限的行为:

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

当我访问 basicURL 时: 我得到以下错误对象:

  "error": 
    "code": 403,
    "message": "Permission denied. Could not perform this operation"
  

当我访问 basicURL?alt=media 我得到相同的错误对象:

  "error": 
    "code": 403,
    "message": "Permission denied. Could not perform this operation"
  

当我访问 basicURL?alt=media&token=TOKEN_VALUE 图像已显示。

结论和问题

在我看来,安全规则 allow read: if request.auth != null; 应该阻止未经授权的用户的任何读取,但使用 TOKEN 参数,即使没有 auth 对象的请求也可以访问该文件(注意:我不是t 在我运行上述测试时登录)。

我知道问超过 1 个问题不是最佳做法,但在这种情况下,我认为这是必要的:

问题 1:

这个 TOKEN 主要用于什么,为什么它超越了auth 规则?

问题 2:

我希望这些图片可以公开使用,因为博客部分将面向所有用户。我应该将哪个 URL 保存到 Firestore?

选项 1: 允许所有人读取并保存 basicURL。

选项 2: 限制读取并保存 basicURL + 令牌。

问题 3:

要在<image src="imgSrc"> 标签中显示图像,我需要alt=media 参数吗?还是以 FILE_NAME 结尾的 basicURL 就够了?

编辑:问题 3 答案: 刚刚对其进行了测试,发现alt=media GET 参数是在<img> 标记内显示图像所必需的。


注意:如果您上传相同的文件并替换旧文件,您每次都会得到不同的token,旧的token 将失效。

【问题讨论】:

恕我直言,谷歌的设计决策非常糟糕 【参考方案1】:
    service firebase.storage 
      match /b/bucket/o 
        match /allPaths=** 
          allow read, write;
        
      
    

这是 Firebase 存储的安全权限。所有类型的数据(图像、视频等)

【讨论】:

【参考方案2】:

不幸的是,https://firebase.google.com/docs/storage/web/create-reference 中描述的方法没有像请求和存储规则一样添加授权数据

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

返回permission denied, 使用 AngularFireStorage 模块可以解决这个问题。

import  AngularFireStorage  from '@angular/fire/storage';

 constructor(     
        private storage: AngularFireStorage
    ) 

    
getFileUrl(path: string): Observable<string>        
        const storageRef = this.storage.ref(path);
        return from(storageRef.getDownloadURL());
    

【讨论】:

以上是关于Firebase 存储安全规则和上传文件的下载令牌的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 11 网站上使用 Firestore 和 Firebase 存储进行图像上传功能导致来自 Firebase 的不安全规则通知

如何为上传到 Firebase 存储的文件生成访问令牌?

Firebase 存储安全规则:指定“允许读取:如果 request.auth != null”后,我仍然可以使用提供的下载链接访问我的文件

添加 Firebase 存储用户上传限制

为特定用户提供访问权限的 Firebase 存储安全规则

Firebase存储安全规则为特定用户提供访问权限