对象存储的数据泄露通常不涉及入侵。没有人攻破系统,没有凭据被盗,日志里也看不出异常。只是配置把数据公开了。
为什么没人入侵数据也会泄露
入侵
漏洞或凭据 → 侵入 → 把数据带走
打补丁、认证、监控都有机会拦住它
配置错误(公开的存储桶)
知道(或猜到)URL → 直接获取
不是「认证被绕过」——而是从来就不需要认证
这类问题难以发现,是因为访问看起来并不违规。攻击者向一个确实公开的端点发送普通的 GET 请求,入侵检测或日志异常几乎抓不到什么。它和绝不能放在公开目录里的东西是同一个问题,只是发生在存储而不是服务器上。
4 项设置各自阻止的东西不同
S3 的阻止公有访问(Block Public Access)由 4 项相互独立的设置组成,可以任意组合。名称相似,容易被当成一个开关,但每一项阻止的东西都不同。
- BlockPublicAcls
- 让设置新的公开 ACL 的操作失败(
PutBucketAcl、PutObjectAcl,或带公开 ACL 的PutObject)。不会修改现有的策略和 ACL,已经存在的公开 ACL 会继续存在 - IgnorePublicAcls
- 让 S3 忽略存储桶及其对象上的所有公开 ACL。带公开 ACL 的
PutObject仍然会成功(这是与 BlockPublicAcls 的区别)。它不会删除现有 ACL,也不会阻止设置新的公开 ACL - BlockPublicPolicy
- 拒绝允许公有访问的存储桶策略(
PutBucketPolicy及相关的访问点调用)。不影响现有的策略 - RestrictPublicBuckets
- 把对带有公开策略的存储桶的访问,限制为 AWS 服务主体和所属账户内的授权用户。它会阻止跨账户访问(AWS 服务主体除外),包括对特定账户的非公开委托
4 项共有、却几乎所有人都忽略的性质
请注意,上面每一项都写着不会修改现有的策略和 ACL。文档直接写出了后果:「阻止公有访问设置不会更改现有的策略或 ACL。因此,解除阻止公有访问设置后,带有公开策略或 ACL 的存储桶或对象会再次变为可公开访问。」
也就是说,开启阻止并没有消除危险。它只是暂时挡住访问,公开的策略和 ACL 仍然在那里。有人为了调查临时解除、复制到另一个账户、Terraform 的差异把它改回去:任何一种都会让数据再次公开。把目标状态定义为「关掉阻止也不公开」,而不是「阻止已开启」。
「公开」的定义比你想的更宽
你认为是私有的存储桶,S3 也可能评估为公开。
被评估为公开
・向 AllUsers 或 AuthenticatedUsers 授予权限的 ACL——后者指的是所有拥有 AWS 账户的人,而不是你公司的所有人
・存储桶策略中指定主体的值含有通配符或策略变量
・aws:SourceIp 的范围过宽(IPv4 宽于 /8,IPv6 宽于 /32,私有地址段除外)
S3 先假定存储桶策略是公开的,再评估它是否符合非公开的条件。模糊不清时就会被评估为公开。
被评估为非公开
把访问限制为不含通配符的固定值的策略——主体、一组 CIDR 地址段、aws:SourceArn、aws:SourceVpc、aws:SourceVpce、aws:SourceOwner、aws:SourceAccount 等。
文档自己的例子:aws:SourceVpc 设为 vpc-* 是公开的;设为 vpc-91237329 这样的固定值则不是。「我缩小了范围」和「我缩小到了固定值」正是这个判断的两面。
在账户级别启用阻止,而不是按存储桶
文档建议在账户级别应用 BlockPublicPolicy,因为存储桶策略可以允许用户修改该存储桶的阻止公有访问设置。
仅存储桶级
能修改存储桶策略的人 → 写入关闭阻止的策略 → 存储桶可以被公开
账户级
即使存储桶策略被改写,S3 也会阻止公开策略
当访问点、存储桶和账户的设置不一致时,S3 会采用最严格的组合。更严格的设置优先,所以在上层(账户)加以限制,下层就无法放宽——这就是把最小权限应用到存储上。
修复的顺序
先看哪些是公开的——在隐藏之前
先开启阻止,确实能止住暴露,但同时也会让你看不到曾经暴露了什么。BlockPublicAcls 的说明正是这样写的:它在防止公有访问的同时,「让你可以审核、细化或以其他方式修改现有的策略和 ACL」。AWS 提供了 IAM Access Analyzer for S3,它会列出 ACL 或策略授予了公有访问的存储桶,并针对每条结果报告访问的来源和级别。先在那里做好清点。
在账户级别启用全部 4 项设置
AWS 建议为账户开启全部 4 项阻止公有访问设置(以及每个存储桶,这是 Security Hub 控制项 S3.8 检查的内容)。先确认你的应用在没有公有访问时能正常工作——如果确实有需要公开的东西,比如静态网站托管,就单独调整那一处,而不是在所有地方都跳过这项控制。
真正删除公开的 ACL 和策略(最重要的一步)
阻止不会删除现有的公开策略或公开 ACL。**回到第 1 步的清单,把它们删除或改写。**只有这样才算进入「关掉阻止也不公开」的状态。大多数团队停在第 2 步,而这正是本文的重点。
对必须公开的存储桶,控制放进去的东西
在确实需要公开访问的地方,把存储分开,让公开存储桶只放可以公开的东西。备份、数据库导出文件、客户名单不要和公开素材放在同一个存储桶里。放进存储桶的东西,决定了它能泄露多少。服务器端的同类思路见在共享主机上让 .env 无法被访问。
不要依赖文件名
「没人知道这个 URL」不是访问控制(与可被猜到的标识符是同一个问题)。**难以猜到的名字只是额外的保护,不能代替权限检查。**需要临时共享时,使用会自动失效的方式——有时间限制的签名 URL——并保持公开设置关闭。
本站的观点:只有状态可被检查,配置类事故才会减少
存储桶暴露反复发生,不是因为人们粗心,而是因为状态看不见。与文件权限或服务器设置不同,存储是否公开是由策略、ACL、账户设置、访问点这 4 层组合决定的,单看其中任何一层都得不出答案。对于这类领域,我们的立场是让机器去评估这个组合,而不是依赖人的注意力:在上层限制,使下层无法放宽;并定期用能直接给出公开/非公开判断的工具重新清点。「小心一点」不是控制手段——这和我们对依赖包得出的结论相同(osv-scanner 入门)。
出处(一手资料)
- Amazon Web Services, "Blocking public access to your Amazon S3 storage"(Amazon S3 用户指南)— docs.aws.amazon.com(4 项设置的行为、阻止不会修改现有策略或 ACL 的说明、「公开」的定义,以及建议在账户级别应用的理由,均出自该文档)
接下来阅读
- 放置位置:绝不能放在公开目录里的东西/在共享主机上让 .env 无法被访问
- 凭据:.env 和 API 密钥的危险在哪里/SSH 密钥与最小权限
- 清点:资产清点检查表
- 同样是「因配置而泄露」:子域名接管与悬空 DNS
FAQ
Q开启了「阻止公有访问」,就安全了吗?
目前处于外部无法访问的状态,但危险并没有消失。AWS 文档写明:阻止公有访问的设置不会修改现有的策略或 ACL,因此解除阻止设置后,带有公开策略或 ACL 的存储桶或对象会再次变成可公开访问。公开的策略和 ACL 仍然留在阻止层下面。你要的不是「阻止已开启」,而是「即使关掉阻止也没有任何东西是公开的」——也就是把公开的策略和 ACL 本身删掉。
Q应该按存储桶设置,还是按账户设置?
按账户设置。文档在 BlockPublicPolicy 的说明里给出了理由:存储桶策略可以允许用户修改该存储桶的阻止公有访问设置,因此能修改存储桶策略的人,就可以写入一条关闭阻止的策略。如果在整个账户启用该设置,即使用户改了存储桶策略,S3 也会阻止公开策略。存储桶级的设置则可以被能编辑存储桶策略的人解除。
Q到底什么算「公开」?
定义比多数人想的更宽。ACL 只要向预定义的 AllUsers 或 AuthenticatedUsers 组授予权限,就算公开——AuthenticatedUsers 指的是所有拥有 AWS 账户的人,而不是你公司的所有人。对于存储桶策略,S3 先假定策略是公开的,再评估它是否符合非公开的条件;只有当访问被限制为不含通配符或策略变量的固定值时才算非公开。使用 aws:SourceIp 且范围很宽(IPv4 宽于 /8)的策略也会被评估为公开。
Q新建的存储桶默认是安全的吗?
文档说,默认情况下新的存储桶、访问点和对象不允许公有访问——但用户可以修改存储桶策略、访问点策略或对象权限来允许它。所以默认值在安全的一侧,而几乎所有事故都发生在有人有意地、或为了某项工作临时偏离默认值的地方。不要依赖默认值:既需要一个在本地无法关闭的控制(账户级阻止),也需要能看出状态何时偏离的手段。