对象存储(OSS)是阿里云上最"顺手"的产品之一,建 Bucket、传文件、拿个外链就能用了。也正因为它上手太快,权限这一层经常被跳过——直到某天安全扫描报出一条"Bucket 可公开访问",或者账单里冒出一笔莫名其妙的外网流出流量费。
这篇文章把 OSS 权限配置拆成一份可执行的清单:先讲清权限控制的生效层级,再给出配置与自查步骤,最后是八条我自己踩过或见别人踩过的坑。
一、先搞懂:OSS 的权限是分层的
很多人的困惑不是"怎么配",而是"我明明把 Bucket 设成私有了,为什么还能被匿名读到"。原因是 OSS 的权限控制不是单一开关,而是多层叠加,每层的生效范围不一样。
生效优先级从高到低如下(官方权限模型):
| 优先级 | 机制 | 作用范围 | 典型用途 |
|---|---|---|---|
| 1(最高) | 阻止公共访问 | Bucket 全局安全开关 | 一个开关封堵所有公共权限 |
| 2 | Bucket Policy | 配置在 Bucket 上的资源共享策略 | 授权其他账号 / 匿名用户,可加 IP、VPC、时间条件 |
| 3 | RAM Policy | 绑定到 RAM 用户身份 | 统一管理某个用户/应用能访问哪些资源 |
| 4 | Bucket ACL | Bucket 级预设权限 | 私有 / 公共读 / 公共读写三档 |
| — | Object ACL | 单个对象 | 优先级高于 Bucket ACL,未设置时继承 Bucket ACL |
几个必须记住的规则:
- 明确拒绝(Explicit Deny)优先级最高。任何一层策略里写了拒绝,其他层的允许都无效。
- 多层策略是"与"的关系。同时配置 Bucket Policy、RAM Policy 时,必须每一层都允许,请求才通过。
- Object ACL 高于 Bucket ACL。Bucket 是私有,但某个对象被单独设成公共读,那这个对象匿名就能读——这是最容易被忽略的一条。
- 阻止公共访问是总闸。开启后,ACL 和 Bucket Policy 里配的公共授权一律失效,新的公共权限也配不上。
二、Bucket ACL 三档到底是什么
Bucket ACL 是最简单的一层,只有三个预设值(另外 Object ACL 多一个"继承 Bucket"):
| 权限值 | 谁能读 | 谁能写 | 官方建议 |
|---|---|---|---|
| private(默认) | 仅拥有者/被授权用户 | 仅拥有者/被授权用户 | 强烈推荐,保持默认 |
| public-read | 任何人(含匿名) | 仅拥有者/被授权用户 | 谨慎使用,必须配防盗链 |
| public-read-write | 任何人(含匿名) | 任何人(含匿名) | 强烈不推荐,常规场景严禁使用 |
public-read-write 意味着互联网上任何人都能往你的 Bucket 里写文件、删文件。除了数据外泄和流量费激增,还可能被写入违规内容,风险等级和"数据库裸奔在公网"是一个量级。
顺带说一个控制台行为:OSS 控制台默认开启"阻止公共访问",因此新建 Bucket 只支持私有权限。如果你确实需要公共读(比如托管网站静态资源),得先到 权限控制 > 阻止公共访问 里关掉该策略,再回到 读写权限 页签修改——很多人卡在"改不了权限",原因就在这里。
三、配置清单:五步把 Bucket 收干净
以下步骤基于 OSS 控制台,路径按当前版本导航栏。
第 1 步:确认阻止公共访问的状态
- Bucket 级:Bucket 详情 →
权限控制 > 阻止公共访问,建议保持开启。 - 账号级:OSS 控制台 →
数据服务 > 阻止公共访问,可以在账号维度统一兜底。 - 生效关系:账号级 > Bucket 级 > 接入点级,高层覆盖低层。账号级开启后,所有 Bucket 的公共访问都会被阻断。
第 2 步:把 Bucket ACL 保持为 private
- 路径:Bucket →
权限控制 > 读写权限→ 设置 → 选"私有" → 保存。 - 如果这里只有"私有"一个选项且无法修改,说明阻止公共访问开着,属正常状态。
第 3 步:检查每一个 Object ACL
不要只看 Bucket 级别。在 Bucket 内按需检查对象权限,重点是历史遗留的图片、安装包等"当年为了省事设成公共读"的文件。批量排查可以用 ossutil:
# 查看 Bucket 的 ACL
ossutil api get-bucket-acl --bucket example-bucket
# 将对象 ACL 改回私有
ossutil api put-object-acl --bucket example-bucket --key path/to/file.png --acl private
第 4 步:需要对外分享时,用 RAM 最小权限而不是公共读
如果只是自家应用要读 OSS,正确做法是建 RAM 用户、只授予这一个 Bucket 的读写权限,把 AK 发给应用;跨账号或需要临时授权时用 RAM 角色 + STS 临时凭证。OSS 内置了 AliyunOSSReadOnlyAccess、AliyunOSSFullAccess 等系统策略可以直接用,但生产环境更推荐自定义策略收窄到具体 Bucket 前缀:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": ["oss:GetObject", "oss:PutObject"],
"Resource": ["acs:oss:*:*:example-bucket/uploads/*"]
}
]
}
这段策略的效果是:该 RAM 用户只能在 example-bucket 的 uploads/ 目录下读写,别的一律碰不到。
第 5 步:确实要公共读时,加防盗链
公共读的资源会被别人直接引用,流量算你的。所以要配防盗链,把来源限制到自己的域名:
- 路径:Bucket →
数据安全 > 防盗链,打开开关。 - Referer 白名单至少写三条:主域名、泛子域名、带端口的本地开发地址。注意
*.example.com不包含裸域名example.com,两个都要写。 - HTTP 与 HTTPS 的 Referer 值不同,两种协议前缀都要列,或者干脆只写域名部分让 OSS 只校验域名。
- 空 Referer 的选择:生产环境建议设为"不允许"(否则浏览器直接粘贴 URL、爬虫脚本都能拿走资源);测试环境可以放开,因为自动化脚本和真机调试会产生大量无 Referer 请求。
- 用了 CDN 的话,记得在 CDN 侧开启回源 Referer 透传,否则 OSS 看到的 Referer 是 CDN 节点域名或空值,白名单会全部误拦。
四、八条避坑清单
- 只改 Bucket ACL,漏掉 Object ACL。对象级权限优先级更高,历史对象要单独排查。
- 以为"阻止公共访问"关了没事。这个开关是总闸,关之前先想清楚是不是每一个 Bucket 都真的需要公共访问。
public-read-write用在常规场景。除了公共资源仓库这类特殊需求,一律不要用。- 防盗链白名单只写
*.example.com。裸域名匹配不到,线上会出现部分资源 403 或漏放行。 - 生产环境允许空 Referer。等于没配防盗链,直接粘贴 URL 就能下载。
- CDN 回源 Referer 未透传。防盗链规则在控制台自测通过,上线后微信端图片大面积空白,多半是这个原因。
- RAM 用户直接挂
AliyunOSSFullAccess。图省事的代价是这台机器的凭证可以操作账号下所有 Bucket。 - AK 写死在代码或前端。浏览器端直传应该用 STS 临时凭证,不要下发长期 AK。
五、怎么确认自己没配错
配置完成后,做三个验证:
# 1. 匿名访问你的对象(不带任何签名),应当返回 403
curl -I https://example-bucket.oss-cn-hangzhou.aliyuncs.com/secrets.db
# 2. 检查账号级和 Bucket 级阻止公共访问状态
ossutil api get-public-access-block
ossutil api get-bucket-public-access-block --bucket example-bucket
# 3. 查看 Bucket 当前 ACL
ossutil api get-bucket-acl --bucket example-bucket
第一条命令是成本最低的自查手段:任何本该私有的对象,用 curl 不带签名能 200 拿到,就说明权限配错了。建议把它写进上线检查项里。
小结
OSS 权限的本质是"默认私有 + 按需授权",而绝大多数事故都来自"当年的某次图省事"。把这份清单走一遍,通常十分钟以内就能完成:确认阻止公共访问开启、Bucket ACL 保持 private、逐个排查 Object ACL、对外分享走 RAM/STS、必须公共读时加防盗链。存储的具体规格和计费以官方页面实时展示为准,配置前建议对照帮助中心最新文档。如果要对账号下的 Bucket 做统一的安全基线检查,也可以借助 云安全中心 的基线检查能力批量发现风险配置。