干云安全这一行的人,大概都经历过那种后背发凉的瞬间:明明只是想让某个前端资源能被公网访问,结果一不小心把整个桶里几百份含身份信息的备份暴露了出去。Amazon S3 的“对象私有”问题,是我这几年看到最多、后果也最直接的安全事故之一。今天不聊理论,结合我自己排查和处理过的案例,把“预防性控制 + 强制执行”这套组合拳彻底拆开讲清楚。
先说结论:S3 对象私有不是靠某一个开关就能保证的。真正可落地的方案,必须在配置源头做预防性控制,让“公共访问”从一开始就配置不上去;同时对存量资源和漏网之鱼做强制执行,用扫描、审计、自动修复把已经出现的风险迅速压下去。两条线缺一不可,缺了哪条,都可能在某个没人注意的角落里埋雷。
1. 先想清楚:S3 对象为什么会和“公开”沾边
1.1 几条常见的翻车路线
我处理过的 S3 对象公开事件里,绝大多数不是黑客攻破了什么,而是配置层面的疏忽。这里列几个典型的翻车场景,大家可以对号入座。
第一种是“静态网站托管改崩了”。有人想用 S3 托管前端静态页面,于是在桶策略里加了一条 Principal: "*" 的只读策略,本意是允许访客加载 JS 和 CSS。但问题在于:这个桶里如果后来放了配置文件、数据库导出、日志压缩包,那这些对象会跟着一起被公网读取。更麻烦的是,很多人给完公读权限后就把这件事忘了,前端资源在 CloudFront 后面跑得挺好,桶里的隐私数据却悄悄裸奔了好几个月。
第二种是“对象 ACL 的历史遗留问题”。在 S3 的早期设计里,对象级别可以通过 ACL 单独设置公共读权限。很多人上传文件时看到“公共读”选项,觉得“我就给这一个文件开一下,应该没事”。但现实往往是:这个“就一下”的文件里躺着几千条用户手机号。旧账号里开启过 ACL 的桶尤其危险,因为存储在对象上的 public-read 授权不会因为你后来改了桶策略就自动消失。
第三种是“跨账户共享写歪了”。有些团队为了和其他账号共享数据,会写一个比较宽松的桶策略,本意是只允许指定账号访问,结果 Principal 写成了 "*",或者把 Action 从 s3:GetObject 扩展成了 s3:*。这类策略问题通常不会被立刻发现,因为它不影响自己人的正常读写,直到某次安全扫描亮起红灯。
第四种和客户端上传有关。如果应用通过预签名 URL 或者 IAM 临时凭证上传对象,而上传时又顺手带了 x-amz-acl: public-read 这个请求头,那对象被创建出来的那一刻就已经对外公开了。这种问题用桶策略很难发现,因为桶策略里并没有任何公网授权,真正的问题隐藏在对象的 ACL 里。
1.2 只堵一个口子远远不够
看到上面这些场景,你可能已经意识到:S3 的公开权限可以来自桶策略,也可以来自对象 ACL,甚至可以来自上传请求参数。入口太多,意味着你不能只靠一道防线。
“预防性控制”解决的是“以后不允许再出错”:比如在账号层面把 Block Public Access 打开、把桶的 ACL 机制禁用、通过组织策略禁止关闭这些开关。预防性控制的特点是前置、自动化、范围大,它让错误配置在提交的那一刻就被拦截。
“强制执行”解决的是“已经出错的东西必须被发现和处理”:比如用 Access Analyzer 检测存量桶是否公开、用 AWS Config 持续审计桶和对象的合规状态、用 EventBridge 捕获配置变更事件并触发自动修复。强制执行处理的是预防性控制还没来得及覆盖的死角,也包括那些在预防策略上线之前就已经存在的历史遗留问题。
如果只做预防,历史桶里已经存在的公共策略没人管;如果只做强制,每次有人设置了公共策略,你都要靠人工去发现和处理,中间的空窗期足够被扫描器抓取好几轮了。两条线拉起来之后,S3 对象私有才能真正变成一个“系统默认状态”,而不是靠某个人每次小心翼翼不出错。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 预防性控制:让“公开”在配置源头就失效
2.1 Block Public Access 四件套分别防什么
S3 Block Public Access 是 AWS 在多次数据泄露事件后推出的“总开关”,很多人知道要开,但不一定清楚它内部四个选项分别挡的是什么。
| 参数 | 含义 | 主要作用 |
|---|---|---|
| BlockPublicAcls | 阻止通过 ACL 授予公共访问权限 | 当有人尝试通过 PutBucketAcl / PutObjectAcl 写入 public-read 等公共授权时,API 会直接拒绝 |
| IgnorePublicAcls | 忽略桶或对象上已有的公共 ACL | 即使对象上挂着历史遗留的公共 ACL,S3 也不会再按公共 ACL 放行访问 |
| BlockPublicPolicy | 阻止桶策略授予公共访问权限 | 当 PutBucketPolicy 的桶策略内容允许匿名主体或所有 AWS 账户访问时,设置会被拒绝 |
| RestrictPublicBuckets | 限制桶策略中的公共访问只对特定服务主体生效 | 进一步收紧,避免同账号下其他授权途径意外获得公开访问能力 |
实际配置时我一般建议直接把四个选项全部打开,不用纠结。对绝大多数私有数据存储场景来说,这四个全开不会带来任何功能损失。可能会有团队担心“以后要托管静态网站怎么办”,但答案很明确:静态网站不应该依赖 S3 的公网直读,而应该用 CloudFront + OAC(Origin Access Control)的方式,让 S3 桶保持私有,CloudFront 以受信任服务身份回源读取。
