Firebase Storage客户端上传自动生成下载令牌的安全问题
使用Firebase客户端SDK的uploadBytes函数向Firebase Storage上传文件时,系统会自动生成下载令牌并包含在响应中。尽管已配置严格规则禁止公共读取权限,但担心该令牌的存在会危及文件安全性。
当前配置的Storage规则如下:
service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read: if false; allow write: if request.resource.contentType.matches('application/pdf') && request.resource.size < 10 * 1024 * 1024 } } }
该规则禁止公共读取,但允许上传小于10MB的PDF文件。上传后的响应示例包含downloadTokens字段:
{ "name": "sample/sample.pdf", "bucket": "test-12345.appspot.com", "generation": "1715231448324075", "metageneration": "1", "contentType": "application/pdf", "timeCreated": "2024-05-09T05:10:48.325Z", "updated": "2024-05-09T05:10:48.325Z", "storageClass": "STANDARD", "size": "3375", "md5Hash": "vd9mAXeW3724WRQ2sqSkRQ==", "contentEncoding": "identity", "contentDisposition": "inline; filename*=utf-8''sample.pdf", "crc32c": "Wn3FaQ==", "etag": "COuvvYnn/4UDEAE=", "downloadTokens": "767eb459-bae2-41ed-9bb3-cf2cad0d71a4" }
担忧恶意用户可通过响应信息猜测文件的公开下载URL,从而破坏文件安全性。由于使用Vercel托管的Next.js API路由存在负载限制,无法采用服务端上传作为替代方案,现咨询:
- 自动生成下载令牌是否为Firebase Storage的默认预期行为?
- 若存在安全隐患,有无无需服务端上传的缓解方法?
回答
1. 自动生成下载令牌是默认预期行为
是的,这是Firebase Storage的默认机制。当通过客户端SDK上传文件时,系统会自动生成一个UUID格式的下载令牌,该令牌作为一种绕过存储规则的访问凭证——只要持有正确的令牌,任何人都可以通过特定URL直接访问文件,不受allow read: if false这类规则的限制。
2. 无需服务端上传的缓解方案
- 替换/清空自动生成的令牌
在上传文件时,自定义元数据并在上传完成后清空系统生成的令牌:
// 上传时自定义元数据(可选,可加入上传者标识) const metadata = { customMetadata: { uploaderUid: auth.currentUser?.uid, // 可选:自定义自己的令牌 customDownloadToken: crypto.randomUUID() } }; // 执行上传 const uploadResult = await uploadBytes(storageRef, file, metadata); // 清空系统自动生成的downloadTokens await updateMetadata(storageRef, { downloadTokens: '' });
后续需要访问文件时,通过Firebase Admin SDK(部署在Cloud Functions等可信环境)生成临时签名URL,而非依赖固定令牌。
- 强化存储规则,限制令牌访问权限
修改规则,让令牌仅对特定用户生效,比如只有上传者本人能访问:
service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow write: if request.resource.contentType.matches('application/pdf') && request.resource.size < 10 * 1024 * 1024; // 允许上传者读取,或持有有效令牌且身份匹配 allow read: if (request.auth != null && request.auth.uid == resource.metadata.uploaderUid) || (request.auth != null && resource.metadata.customDownloadToken == request.query.token); } } }
这种方式下,即使令牌泄露,没有对应身份的用户也无法访问文件。
- 定期轮换令牌
如果需要长期控制文件访问,可定期通过Admin SDK调用updateMetadata更新downloadTokens字段,替换为新的随机字符串,旧令牌会立即失效。这种操作可以通过Cloud Functions定时触发,无需手动干预。
内容的提问来源于stack exchange,提问作者Kavindu Wijesekara

