3

我正在尝试生成指向 API Gateway 的预签名链接(使用 IAM 身份验证),因此客户端可以访问此 API Gateway 后面的我的 Lambda 函数之一,而无需验证请求。这主要是为了方便客户端,因此它可以透明地使用响应中的一些链接,无论它们指向同一个经过身份验证的 API 网关、某个 S3 存储桶还是 Internet 中的任意 URL。

为此,我使用查询参数制作 API 签名 v4(请参阅文档示例

因此,如果我尝试签署以下us-west-2区域和execute-api服务范围的链接:

https://example.com/some/path?some=params

我会得到以下结果(使用 Node.jsaws4,但在这里没关系):

https://example.com/some/path?some=params&
X-Amz-Security-Token=<Session Token Removed>
X-Amz-Date=20210330T180303Z&
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=<Access Key Removed>%2F20210330%2Fus-west-2%2Fexecute-api%2Faws4_request&
X-Amz-SignedHeaders=host&
X-Amz-Signature=884f132ad6f0c7a850e6b1d22b5fed169c13e2189b6e0d0d568d11f967f4a8bd

它有效!但仅在生成后的前 5 分钟......</p>

五分钟后,我将收到以下错误响应:

{"message":"Signature expired: 20210330T175821Z is now earlier than 20210330T180403Z (20210330T180903Z - 5 min.)"}

有关更多详细信息,请参阅对此问题的回复。

我尝试X-Amz-Expires使用各种值(小于和大于 300 秒)添加文档中提到的查询参数,但没有运气:行为不会改变。

对于由 IAM 实例凭证生成的链接,我需要至少几个小时,最多允许 6 小时,因为链接正在由另一个 Lambda 函数签名。

有什么方法可以增加 API 网关访问的预签名链接有效期?

4

2 回答 2

10

这是一个非常有趣的问题!起初,我认为X-Amz-Expires所有服务(包括 API 网关)都支持的 S3 文档中清楚地记录了它。[1][2]

经过一番研究,事实证明,除了 S3 以外的服务是否支持该参数,这一点并不那么清楚X-Amz-Expires

有各种消息来源声称只有 S3 尊重该参数。以下是 AWS 员工在 aws-sdk for go 上工作的声明:

过期时间仅与 S3 服务相关。其他服务有自己固定的过期时间。通常这是 15 分钟,但看起来物联网数据服务使用 5 分钟的到期时间。[3]

他们跟进:

SDK 没有任何可用的元数据数据来提供哪些服务使用或不使用到期值。[4]

然后在 GitHub 上对应的源码中添加注释:

所有其他 AWS 服务将使用 15 分钟的固定到期时间。[5]

有大量示例表明 AWS 正在使用 S3 服务的参数,例如 [1][6]。但是,AWS 文档中也有一些示例显示了 IAM 服务的参数的使用,例如 [7][8]。这很令人困惑。

AWS 的 SDE 发表评论可以追溯到 2018 年,他在其中发表了同样令人困惑的观察 [9]:

如果 S3 是唯一支持此标头的服务,我同意更新 SDK 的文档以反映这一点 - 在 S3 的 SigV4 文档中包含此标头的描述中的注释,说明此标头是此服务的预签名 URL 独有的有帮助。

FWIW 我与 AWS Auth 的一些人进行了交谈,他们知道使用标头的唯一服务是 S3(有趣的是,您使用 IAM 找到了代码示例)。他们建议 STS 预签名 URL 的 15 分钟到期不会改变。

另一位前 AWS 员工进一步注意到:

我能够使用 EC2、IAM、STS 和 Route 53 的预签名 URL 在适用于 Go 和 PHP 的 AWS 开发工具包上重现此行为。我观察到的唯一服务在“x-amz”中指定的时间后使预签名 URL 无效-expires" 标头(而不是默认的 15 分钟)是 S3。

因此,我想不可能增加 API 网关访问的预签名链接有效期。我认为 AWS 没有设计签名签名算法来支持您的用例。我认为 S3 预签名 URL 操作是 AWS 允许延长到期期限的少数例外情况之一。

当查看他们创建签名算法的动机时,我注意到他们试图最小化重放攻击的攻击面:

防范潜在的重放攻击
在大多数情况下,请求必须在请求时间戳的五分钟内到达 AWS。否则,AWS 会拒绝该请求。[10]

还有一些更多的资源 [11][12] 得出的结论是,让客户选择冗长的到期值会破坏该参数的原始安全目的

我认为没有通用的方法可以为 AWS 服务的 REST API 创建预签名 URL 并在很远的将来执行它。

如果我在你的位置,我会使用 JWT 和 API Gateway Lambda 授权者实施自定义身份验证策略。[13] 这样您就可以自行控制签名算法,尤其是其到期时间。我想补充一点,JWT 与 AWS 签名查询字符串参数一样是 URL 安全的。[14]

[1] https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
[2] https://docs.aws.amazon.com/general/latest/gr /sigv4-add-signature-to-request.html
[3] https://github.com/aws/aws-sdk-go/issues/2304#issuecomment-441755864
[4] https://github.com/aws /aws-sdk-go/issues/2304#issuecomment-441758599
[5] https://github.com/aws/aws-sdk-go/blob/6212dfa8032336d438c526c086918c8d2ceb6432/aws/request/request.go#L310
[6] https ://github.com/mhart/aws4/blob/master/aws4.js#L130
[7] https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
[8]https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
[9] https://github.com/aws/aws-sdk-go/issues/ 2167#issuecomment-428764319
[10] https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html
[11] https://aws.amazon.com/de/articles/making-secure- requests-to-amazon-web-services/?nc1=h_ls(“重放攻击”部分)
[12] https://stackoverflow.com/a/12267408/10473469
[13] https://docs.aws.amazon。 com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
[14] https://stackoverflow.com/a/56273952/10473469

于 2021-04-06T01:02:58.430 回答
1

对于其中一个用例,我也在为此苦苦挣扎。就像用户想要在有限的时间内访问 S3 中的 CSV 文件一样。

我最终构建了以下架构:

  • 一个处理“用户访问请求”的 lambda 函数。它位于 API 网关后面,负责将 CSV 文件放入 S3(您可能不需要此部分)。Lambda 正在生成一个带有一些散列的 URL,触发了 API GW 后面的另一个 lambda (#2)。
  • 我拥有的第二个 lambda 也落后于 API GW,并且可以由第一个 lambda 生成的 URL 触发。这是用户出现的地方,因为来自第一个 lambda 的 URL 被提供给实际用户以点击它。第二个 lambda 所做的很简单。它为 S3 对象动态生成了一个 6 小时长的预签名 URL,并发送回一个带有预签名 URL 的 HTTP 302,因此用户的浏览器会立即下载 CSV。

这样,几乎可以与任何人共享 lambda 生成的 URL,并且该 URL 将一直有效,直到 S3 对象存在。

如果您需要某种策略以使 URL 可访问 30 天或其他时间,您可以设置存储桶策略以在之后摆脱该对象。

于 2021-04-11T09:02:25.400 回答