在getSignedUrl到期后,AWS S3正常处理403

Jam*_*and 5 amazon-s3 amazon-web-services http-status-code-403 pre-signed-url

我正在尝试通过过期的URL访问S3资源时优雅地处理403.目前它返回一个amz xml错误页面.我上传了一个403.html资源,并认为我可以重定向到该资源.

存储区资源是我的应用程序保存/提取的资产.仍然,阅读文档我设置存储桶属性以将存储桶作为静态网页页面处理,并将403.html上传到存储桶根目录.除了对资源403.html的公共GET访问权限外,所有公共权限都被阻止.在存储桶属性,网站设置中,我将403.html指示为错误页面.http://<bucket>.s3-website-us-east-1.amazonaws.com/some-asset.html正确访问重定向到http://<bucket>.s3-website-us-east-1.amazonaws.com/403.html

但是,当我使用aws-sdk js/node和call方法getSignedUrl('getObject', params)生成签名的url时,它会返回不同的主机url:https://<bucket>.s3.amazonaws.com/从此方法访问过期的资源不会被重定向到403.html.我猜测,由于主机地址不同,这就是它不会自动重定向的原因.

我还为条件设置了静态网站路由规则

<Condition>
  <HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
  <ReplaceKeyWith>403.html</ReplaceKeyWith>
</Redirect>
Run Code Online (Sandbox Code Playgroud)

仍然没有重定向签名的网址.所以我不知道如何优雅地处理这些过期的网址.任何帮助将不胜感激.

Mic*_*bot 9

S3存储桶有2个面向公众的接口,REST和网站.这就是两个主机名之间的差异,以及您所看到的行为差异.

它们有两个不同的功能集.

feature          REST Endpoint       Website Endpoint
---------------- ------------------- -------------------
Access control   yes                 no, public content only
Error messages   XML                 HTML
Redirection      no                  yes, bucket, rule, and object-level
Request types    all supported       GET and HEAD only
Root of bucket   lists keys          returns index document
SSL              yes                 no
Run Code Online (Sandbox Code Playgroud)

资料来源:http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html

因此,从表中可以看出,REST端点支持签名URL,但不支持友好错误,而网站端点支持友好错误,但不支持签名URL.这两者不能混合和匹配,因此S3尝试做的不是本机支持的.


我通过在EC2实例上将所有桶请求通过HAProxy传递到存储桶的REST端点来解决此限制.

当返回403错误消息时,代理使用新的嵌入式Lua解释器修改响应主体XML ,在<Error>标记之前添加它.

<?xml-stylesheet type="text/xsl" href="/error.xsl"?>\n
Run Code Online (Sandbox Code Playgroud)

该文件/error.xsl是公共可读的,并使用浏览器端XSLT呈现非常错误的响应.

代理还会在xml中注入一些额外的标记,<ProxyTime><ProxyHTTPCode>用于输出.生成的XML如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/error.xsl"?>
<Error><ProxyTime>2015-10-13T17:36:01Z</ProxyTime><ProxyHTTPCode>403</ProxyHTTPCode><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>9D3E05D20C1BD6AC</RequestId><HostId>WvdkvIRIDMjfa/1Oi3DGVOTR0hABCDEFGHIJKLMNOPQRSTUVWXYZ+B8thZahg7W/I/ExAmPlEAQ=</HostId></Error>
Run Code Online (Sandbox Code Playgroud)

然后我通过XSL测试改变向用户显示的输出,以确定S3抛出的错误条件:

<xsl:if test="//Code = 'AccessDenied'">
  <p>It seems we may have provided you with a link to a resource to which you do not have access, or a resource which does not exist, or that our internal security mechanisms were unable to reach consensus on your authorization to view it.</p>
</xsl:if>
Run Code Online (Sandbox Code Playgroud)

最终结果如下:

浏览器截图此行为的示例

以上是一般的"拒绝访问",因为没有提供凭据.这是过期签名的示例.

过期签名的屏幕截图

我没有HostId在输出中包含它,因为它是丑陋和嘈杂的,并且,如果我需要它,代理捕获并记录它为我,我可以交叉引用请求ID.

当然,作为奖励,通过我的代理运行请求意味着我可以在提供存储桶内容时使用我自己的域名我自己的SSL证书,并且我有实时访问日志,没有延迟.当代理与存储区位于同一区域时,数据传输的额外步骤不会产生额外费用,我对此设置非常满意.