S3 上传与服务器端加密不兼容

我正在尝试将现有的 Discourse 服务器迁移到一个新的基于 AWS 的环境中,将上传存储在 S3 存储桶中,并使用客户管理的密钥 (SSE-C) 进行服务器端加密。在恢复过程中,上传没有进入 S3 —— 每次上传都失败。通过谨慎使用 tap|p 调试,我发现上传已完成,但返回的 etag 验证失败,因为每次从 S3 上传后返回的 etag 都不同。例如,这是在两次不同的恢复尝试中 put_object 调用 的返回值:

# 运行 1
# <struct Aws::S3::Types::PutObjectOutput expiration=nil, etag="\"d49ec2006cfd6fe957af2f711edd9a4b\"", checksum_crc32=nil, checksum_crc32c=nil, checksum_sha1=nil, checksum_sha256=nil, server_side_encryption="aws:kms", version_id="xAF23wQ.zwpoxVmmGiTjxfX0svMZbHAe", sse_customer_algorithm=nil, sse_customer_key_md5=nil, ssekms_key_id="**redacted**", ssekms_encryption_context=nil, bucket_key_enabled=true, request_charged=nil>

# 运行 2:
# <struct Aws::S3::Types::PutObjectOutput expiration=nil, etag="\"05edffee421c6aef950b3d4418ada293\"", checksum_crc32=nil, checksum_crc32c=nil, checksum_sha1=nil, checksum_sha256=nil, server_side_encryption="aws:kms", version_id="H2_8SVh.Yx2LKB4GIjhyPbVoj_.Vc1E2", sse_customer_algorithm=nil, sse_customer_key_md5=nil, ssekms_key_id="**redacted**", ssekms_encryption_context=nil, bucket_key_enabled=true, request_charged=nil>

(我知道这些是相同的文件,因为我还打印了客户端 MD5 校验和和 put_object 请求选项,其中包含文件名)

事实证明,ETag 响应头 在使用 SSE-C 时表现……不同:

使用客户提供的密钥 (SSE-C) 或 AWS Key Management Service (AWS KMS) 密钥 (SSE-KMS) 进行服务器端加密的对象,其 ETag 不是其对象数据的 MD5 摘要。

我能找到的唯一一种方法是使用 SSE-C 进行上传完整性验证,即发送 Content-MD5 请求头,让 S3 进行损坏检测。另外请注意,已上传检查 在使用 SSE-C 时也会中断,但至少可以使用 SKIP_ETAG_VERIFY 禁用它。

我没有立即提交 PR,因为有两种方法可以解决这个问题:

  1. 只需将 SKIP_ETAG_VERIFY 扩展到包含上传后验证,这是一种廉价且粗糙的方法,需要用户知道他们使用 SSE-C 意味着他们必须打开它;或者
  2. 切换到使用 Content-MD5 头(最好是始终使用)进行上传完整性保护,这有一个好处是适用于所有人,但代价是一个更大的 PR。

(顺便说一句,我相当震惊没有人之前遇到过这个问题——难道没有人使用 Discourse 和 SSE-C 进行上传吗?!?)

4 个赞

我猜“安全上传”只在非常特定的情况下使用,这意味着 99.8% 的上传都是公开提供的,这使得任何形式的静态加密都变得毫无用处?

Matt,你没有说错,据我所知,这是第一次提出这个问题。

在我看来,(2) 是正确的方法,如果你能做到的话。

否则,我想你不会对所有文件都正确存放有信心。

一旦你将所有上传内容都放入你的 S3 存储桶,Discourse 的常规运行是否正常?日常使用是否需要其他更改(想想像库存可能会出问题——也许需要更改预签名 URL 等)?

5 个赞

我会尝试处理。幸运的是,找到所有提到“etag”的地方应该足以找到所有需要更改的代码位置,而且测试套件布局合理,我可以轻松找到需要运行和更改的内容。

至于其他可能出错的地方,我还没有成功搭建一个可用的网站,我会一边进行一边报告/提交PR。库存应该不会出错,因为只有文件内容被加密,而不是名称。我可能不会发现预签名URL是否会出错,因为我没有使用它们。

3 个赞

我刚刚打开了 这个 PR,它在迁移到 S3 时移除了基于 ETag 的上传验证。事实证明,它在迁移到 S3 时使用;在常规上传时,它只是 YOLO(随它去),这让我的工作轻松了很多。有了这个 PR 和之前提交的 ACL 禁用站点设置 PR,我现在已经完成了恢复。下一步:测试功能。

6 个赞

我认为这现在已经合并了。 :partying_face:

1 个赞

此主题已在 2 天后自动关闭。不再允许回复。