You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS S3 V2预签名URL提前过期:X-Amz-Security-Token失效求助

解决S3 Signature V2预签名URL提前过期的问题

我来帮你拆解问题根源并给出可行的解决方案:

为什么你的URL会1天就过期?

你遇到的问题其实是两个限制叠加导致的:

  1. S3预签名URL的固有上限:不管是Signature V2还是V4,S3原生预签名URL的最大有效时长都是7天(604800秒)——你设置的2592000(30天)已经超出了这个限制,AWS会自动截断到7天,但这还不是你1天就失效的直接原因。
  2. Lambda临时凭证的有效期限制:你的Lambda函数用的是IAM角色的临时安全凭证,这类凭证默认有效期只有1小时,最多能延长到12小时(通过IAM角色配置)。预签名URL的有效期绝对不能超过生成它的凭证的有效期——哪怕你设了7天的Expires,一旦Lambda的临时凭证过期,URL就会直接失效。你看到的1天过期,大概率是你的IAM角色会话时长被配置成了24小时,但这依然远达不到30天的需求。

要实现1个月有效期的访问链接,该怎么做?

因为S3原生预签名URL最长只能到7天,要实现30天的有效期,有两个方向可选:

方案1:改用CloudFront签名URL(推荐,支持最长1年有效期)

这是AWS官方推荐的长期访问S3资源的方案,步骤大概是:

  • 创建CloudFront分发,把源指向你的S3存储桶,配置好缓存规则和访问控制(比如限制只有签名URL能访问)。
  • 在IAM中创建一个专门用于签名CloudFront URL的身份(可以用IAM用户的长期凭证,或者用角色生成临时凭证——不过CloudFront签名支持的临时凭证最长也能到12小时,你可以定期生成新的URL)。
  • 用AWS SDK生成CloudFront签名URL,把Expires设为30天后的UNIX时间戳(注意这里是具体的时间点,不是秒数)。

方案2:临时优化Lambda凭证(仅能延长到12小时内,不满足30天需求)

如果你的需求可以妥协到12小时内的有效期,可以按以下步骤调整:

  1. 打开IAM控制台,找到Lambda关联的角色,编辑它的信任策略,添加允许更长会话时长的条件:
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole",
          "Condition": {
            "NumericLessThanEquals": {
              "sts:DurationSeconds": 43200
            }
          }
        }
      ]
    }
    
  2. 在该角色的“信任关系”标签页,把MaxSessionDuration改成43200秒(也就是12小时)。
  3. 修改Lambda代码,主动获取长时长的临时凭证来生成预签名URL:
    const AWS = require('aws-sdk');
    
    async function getLongLivedCredentials() {
      const sts = new AWS.STS();
      const roleArn = 'arn:aws:iam::你的账号ID:role/你的Lambda角色名';
      const params = {
        RoleArn: roleArn,
        RoleSessionName: 'long-lived-s3-session',
        DurationSeconds: 43200 // 不能超过角色设置的MaxSessionDuration
      };
      const data = await sts.assumeRole(params).promise();
      return {
        accessKeyId: data.Credentials.AccessKeyId,
        secretAccessKey: data.Credentials.SecretAccessKey,
        sessionToken: data.Credentials.SessionToken
      };
    }
    
    exports.handler = async (event) => {
      const creds = await getLongLivedCredentials();
      const s3 = new AWS.S3({
        signatureVersion: 'v2',
        region: 'eu-west-1',
        credentials: creds
      });
      const bucketParam = {
        Bucket: 'test-bucket',
        Key: 'testFile-1111-2222',
        Expires: 43200 // 必须小于等于凭证的有效期
      };
      const signedUrl = s3.getSignedUrl('getObject', bucketParam);
      return { signedUrl };
    };
    
    这里要注意:Expires的值必须小于等于你获取的凭证的有效期,否则URL还是会在凭证过期时失效。

重要提醒

  • 绝对不要用长期IAM用户凭证来生成S3预签名URL——长期凭证一旦泄露,你的存储桶安全会面临极大风险。
  • CloudFront签名URL不仅支持更长的有效期,还能加IP限制、自定义访问策略等额外安全控制,是长期访问S3资源的最佳实践。

内容的提问来源于stack exchange,提问作者StrawHat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:16:48