AWS S3 预签名 URL,无到期日

问题描述 投票:0回答:6

有什么方法可以生成没有任何到期日期的预签名 URL? 我正在开发一个电子邮件应用程序,我的附件将保存在 S3 中。 另请告诉我通过 JavaScript SDK 下载附件的最佳方式是什么。

我正在使用下面的代码

var params = {Bucket: 'bucket', Key: 'key', Expires: 60};
var url = s3.getSignedUrl('getObject', params);
console.log('The URL is', url);
amazon-web-services amazon-s3 pre-signed-url
6个回答
129
投票

预签名 URL 的最长过期时间为自创建之日起一周。所以没有办法让预签名的 url 没有过期时间。


42
投票

这取决于您如何生成 S3 预签名 URL。具体来说,您使用哪个签名版本以及您使用什么类型的 IAM 凭证。

可用于创建预签名 URL 的凭据包括:

  • IAM 实例配置文件(临时、轮换凭证):有效期最长为 6 小时
  • STS(临时凭证):有效期最长为 36 小时
  • IAM 用户(长期凭证):使用签名 v4 时有效期最长为 7 天
  • IAM 用户(长期凭证):使用签名 v2 时,有效期至 纪元结束
特别注意:

    签名 v2
  • 可能已弃用
  • 签名 v2 的过期限制与签名 v4 不同
  • signature v4 比 v2 提供一些
  • 安全性和效率优势 如果您使用 STS 凭证生成预签名 URL,则该 URL 将在 STS 凭证过期时过期(如果该过期时间早于您为预签名 URL 请求的显式过期时间)
  • 创建在纪元结束前有效的预签名 URL 并不是最佳安全实践
  • 更多请参见:

    为什么我的 Amazon S3 存储桶的预签名 URL 提前过期?
  • 亚马逊s3生成的链接最长过期时间是多少?

20
投票


1
投票

将附件上传到 S3 时,您会生成一个带有文件名的令牌,即 JWT 令牌。
  1. 将令牌保存在 DynamoDB 中,如果需要,可能会包含到期日期
  2. 将 API Gateway URL 和生成的 token 返回给用户,例如
  3. https://get-your-attachment.io/download?token=123 如果令牌过期,请使用 DynamoDB 流在 S3 中查找该文件并将其从 S3 中删除以将其清理
  4. 如果用户想要下载文件,他们会打开步骤 3 中提供的 URL。API Gateway 调用授权 Lambda。此 Lambda 检查令牌是否仍在 DynamoDB 中。如果是,该请求将触发另一个 Lambda 函数,该函数将从令牌中提取文件名并返回文件。您必须返回编码的文件,正确设置响应标头并注意
服务限制

如果下载只能在您的应用程序内完成,并且链接无法在应用程序外部共享或使用,那么您可以跳过通过 API 网关返回文件。授权将保持如上所述。但 Lambda 函数不返回文件,而是返回一个预签名的 URL,有效期可能为 10 分钟。您的应用程序使用该 URL 进行另一个请求并从 S3 接收文件。

至于你问题的第二部分如何下载文件,简单

fetch(preSignedS3URL)

就足够了。

    


0
投票

这里是使用

javascript

的示例,但您可以根据自己的需要进行调整:

const express = require("express");
const { GetObjectCommand, S3Client } = require("@aws-sdk/client-s3");
const app = express();
const port = 5000;

const client = new S3Client({});

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.get("*", async function (req, res, next) {
  console.log(req.url);
  if (req.url.startsWith("/photos")) {
    const command = new GetObjectCommand({
      Bucket: "test-bucket",
      Key: req.url.slice(7),
    });

    try {
      const response = await client.send(command);
      const str = await response.Body.transformToByteArray();

      res.writeHead(200, { "Content-Type": "image/jpeg" });
      res.write(str, "binary");
      res.end(null, "binary");
    } catch (err) {
      console.error(err);
    }
  } else {
    return next();
  }
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

这样,您就可以在电子邮件中使用了
https://your-production-url/photos/whatever-your-object-key-is.jpg

,没有任何问题。

    


-15
投票

const image = image.split('&Expires')[0]

这是我使用的解决方法之一

© www.soinside.com 2019 - 2024. All rights reserved.