如何将 API Gateway 的 AWS 签名 v4 预签名链接的过期时间从默认 5 分钟增加到? [英] How to increase expiration time in AWS signature v4 pre-signed links for API Gateway from default 5 min?

查看:19
本文介绍了如何将 API Gateway 的 AWS 签名 v4 预签名链接的过期时间从默认 5 分钟增加到?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

我将得到以下结果(使用 Node.js aws4,但这里无关紧要):

https://example.com/some/path?some=params&X-Amz-Security-Token=<会话令牌已删除>X-Amz-Date=20210330T180303Z&X-Amz-算法=AWS4-HMAC-SHA256&X-Amz-Credential=<访问密钥已删除>%2F20210330%2Fus-west-2%2Fexecute-api%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=884f132ad6f0c7a850e6b1d22b5fed169c13e2189b6e0d0d568d11f967f4a8bd

它有效!但只有在生成后的前 5 分钟......

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

{message":Signature expired: 20210330T175821Z 现在早于 20210330T180403Z(20210330T180903Z - 5 分钟)"

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

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

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

有没有办法增加 API Gateway 访问的预签名链接有效期?

解决方案

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

经过更多研究,结果证明对于 S3 以外的服务是否支持 X-Amz-Expires 参数完全不清楚.

有各种消息来源声称只有 S3 遵守该参数.以下是一位从事 aws-sdk for go 的 AWS 员工的声明:

<块引用>

过期时间仅与 S3 服务相关.其他服务有自己固定的过期时间.通常这是 15 分钟,但看起来 IoT 数据服务使用了 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 员工进一步注意到:

<块引用>

我能够在适用于 Go 和 PHP 的 AWS 开发工具包上使用 EC2、IAM、STS 和 Route 53 的预签名 URL 重现此行为.我观察到的唯一一项在中指定的时间之后使预签名 URL 失效的服务";x-amz-到期"标头(而不是默认的 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/最新/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

I'm trying to generate a presigned link to API Gateway (that uses IAM authentication), so client may access one of my Lambda functions behind this API Gateway without authenticating request. This is mostly for client convenience, so it may use some links from response transparently, whether they points to the same authenticated API Gateway, some S3 bucket or any arbitrary URL in the Internet.

To do so, I crafting API signature v4 using query parameters (see docs and example)

So, if I try to sign following link scoped for us-west-2 region and execute-api service:

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

I will get following result (using Node.js aws4 library, but it doesn't matter here):

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

And it works! But only first 5 minutes after generation…

After five minutes passed, I will get following error in response:

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

See this response to this question for more details.

I've tried to add X-Amz-Expires query parameter mentioned in the docs with various values (both less and greater than 300 seconds), but with no luck: behavior doesn't change.

I need at least a few hours, up to allowed 6 hours for links generated by IAM instance credentials, as links are being signed by another Lambda function.

Is there any way to increase pre-signed link validity duration for API Gateway access?

解决方案

This is a very interesting question! At first, I thought it is clearly documented in the S3 docs that X-Amz-Expires is supported by all services (including API Gateway). [1][2]

After some more research, it turned out that it is not so clear at all if services other than S3 support the X-Amz-Expires parameter.

There are various sources claiming that only S3 is respecting the parameter. The following is a statement by an AWS employee working on the aws-sdk for go:

The expires time is only relevant for the S3 service. Other services have their own fixed expiration time. Generally this is 15 minutes, but it looks like IoT data service uses a 5 minute expiration time. [3]

They followed up with:

The SDK doesn't have any metadata data available providing which services do or do not use the expiry value. [4]

Then adding a note into the corresponding source code on GitHub:

All other AWS services will use a fixed expiration time of 15 minutes. [5]

There are a ton of examples that show that AWS is using the parameter for the S3 service, e.g. [1][6]. However, there are also examples from AWS docs that show the use of the parameter for the IAM service, e.g. [7][8]. That is very confusing.

There is a comment by an SDE at AWS which is dated back to 2018 in which he makes the same confusing observation [9]:

If S3 is the only service that supports this header I agree that the SDK's documentation should be updated to reflect that - including a note in the description for this header in S3's SigV4 documentation stating that this header is exclusive to presigned URLs for this service would also be helpful.

FWIW I spoke to some folks from AWS Auth and the only service they know of using the header is S3 (interesting that you found a code sample using IAM). They suggested that the 15 minute expiration for STS presigned URLs would not be changing.

Another former AWS employee further noticed:

I was able to reproduce this behavior both on the AWS SDKs for Go and PHP with presigned URLs for EC2, IAM, STS, and Route 53. The only service I observed that invalidated a presigned URL after the time specified in the "x-amz-expires" header (instead of the default 15 minutes) was S3.

Thus, I guess it is not possible to increase pre-signed link validity duration for API Gateway access. I think that AWS did not design the signature signing algorithm to support your use case. I think that the S3 presigned URL action is one of the rare exceptions for which AWS allows an extended expiry period.

When looking at their motivation behind creating the signing algorithm the way it is, I noticed that they try to minimize the attack surface for replay attacks:

Protect against potential replay attacks
In most cases, a request must reach AWS within five minutes of the time stamp in the request. Otherwise, AWS denies the request. [10]

There are some more resources [11][12] that lead to the conclusion that letting customers choose lengthy expiry values would undermine the original security purpose of that parameter.

I think there is no generic way to create a presigned URL towards an AWS service's REST API and execute it far in the future.

If I were in your place, I would implement a custom authentication strategy using JWTs and API Gateway Lambda authorizers. [13] That way you can control the signing algorithm and particulary its expiration time on your own. I want to add that JWTs are URL-safe in the same way AWS signature query string parameters are. [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 (section "Replay Attacks")
[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

这篇关于如何将 API Gateway 的 AWS 签名 v4 预签名链接的过期时间从默认 5 分钟增加到?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆