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

如何验证AWS SigV4签名?S3多区域访问点预签名URL校验

验证S3多区域访问点(MRAP)v4a预签名URL的签名真实性

我已经通过AWS为多区域访问点(MRAP)生成了用于获取S3对象的v4a签名预签名URL,生成代码如下:

from abc import ABC, abstractmethod
from enum import Enum
from typing import List, Optional, Tuple, TypedDict, Union, Dict
import json
import hmac
import hashlib
import urllib.parse

from aiobotocore.client import AioBaseClient
from botocore import awsrequest  # type: ignore
from botocore.credentials import Credentials  # type: ignore
from botocore.crt.auth import CrtS3SigV4AsymQueryAuth  # type: ignore

class S3Creds(TypedDict):
    """S3 creds."""

    aws_access_key_id: str
    aws_secret_access_key: str
    aws_session_token: Optional[str]

class MRAPSigner(AWSStorageResourceSigner):
    """AWS MRAP Signer."""

    def __init__(
        self,
        endpoint: str,
        creds: S3Creds,
    ) -> None:
        """Initialize MRAPSigner."""
        self._region = "*"
        self._endpoint = endpoint
        self._creds = Credentials(
            access_key=creds["aws_access_key_id"],
            secret_key=creds["aws_secret_access_key"],
            token=creds["aws_session_token"],
        )
        self._s3_sig_v4_asym_query_auth = CrtS3SigV4AsymQueryAuth(
            self._creds,
            "s3",
            self._region,
        )

    def generate_presigned_url(
        self,
        method: S3Method,
        item: str,
        file_type: Optional[str] = None,
    ) -> str:
        """Generate presigned url.

        Known Issue:
            - This function should be called not too late \
                (like several minutes) after the creation of the signer.
        """
        aws_request_config: Dict[str, Union[str, Dict]] = {
            "method": method.value,
            "url": self._endpoint + "/" + item,
        }
        if method == S3Method.PUT and file_type:
            headers: Dict[str, str] = {}
            headers["content-type"] = file_type
            aws_request_config["headers"] = headers
        asymmetric_query_request = awsrequest.AWSRequest(**aws_request_config)
        self._s3_sig_v4_asym_query_auth.add_auth(asymmetric_query_request)
        prepared_asymmetric_query = asymmetric_query_request.prepare()
        return prepared_asymmetric_query.url

我希望无需打开生成的URL,直接通过验证签名来确认其真实性,恳请提供相关帮助。我已查阅AWS官方文档中的《使用查询字符串进行身份验证》和《使用HTTP标头进行身份验证》内容。


验证步骤详解

v4a是S3多区域访问点专用的非对称签名变体,验证逻辑基于SigV4规范但有特殊适配,具体步骤如下:

1. 解析预签名URL的核心参数

先将目标URL解析为查询参数集合,提取以下关键字段:

  • X-Amz-Algorithm:确认值为AWS4-HMAC-SHA256(v4a的算法标识与标准SigV4一致)
  • X-Amz-Credential:格式为AKIAXXX/*/s3/aws4_request,其中*是MRAP特有的通配符区域标识
  • X-Amz-Date:签名生成的ISO8601格式时间戳
  • X-Amz-SignedHeaders:签名覆盖的请求头列表(分号分隔)
  • X-Amz-Signature:待验证的签名值
  • (可选)X-Amz-Security-Token:临时凭证的会话令牌(如果生成URL时用了临时密钥)

2. 重构待签名的请求字符串

按照SigV4a规则,依次构建规范化请求和待签名字符串:

2.1 构建规范化请求

规范化请求格式固定为:

<HTTP方法>
<规范化URI>
<规范化查询字符串>
<规范化请求头>\n
<已签名头>
<负载哈希值>

各部分说明:

  • HTTP方法:必须与生成URL时使用的方法完全一致(如GET/PUT)
  • 规范化URI:去掉MRAP端点域名后的路径部分,例如端点为https://mrap-id.s3.dualstack.us-east-1.amazonaws.com、对象路径为docs/report.pdf,则URI为/docs/report.pdf
  • 规范化查询字符串:移除X-Amz-Signature后,将剩余查询参数按字典序排序,键值对以key=value格式拼接,用&分隔(注意先对参数值做URL解码)
  • 规范化请求头:将X-Amz-SignedHeaders中的头名转为小写,按字典序排序后格式化为key:value\n,最后追加一个空行
  • 已签名头:直接使用X-Amz-SignedHeaders的原始值(已排序的小写头名,分号分隔)
  • 负载哈希值:GET请求负载为空,固定哈希值为e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855;PUT请求需与生成URL时指定的content-type对应,若未指定负载则同样使用空负载哈希

2.2 构建待签名字符串

待签名字符串格式为:

AWS4-HMAC-SHA256
<X-Amz-Date>
*/s3/aws4_request
<规范化请求的SHA256哈希值>

注意这里的区域部分固定为*,是MRAP签名的核心特征。

3. 计算签名并对比验证

使用生成URL时的AWS密钥,按照SigV4a的密钥派生规则计算签名:

  1. 生成基础密钥:k_secret = "AWS4" + <AWS_SECRET_ACCESS_KEY>
  2. 生成区域密钥:k_region = hmac.new(k_secret.encode(), "*".encode(), hashlib.sha256).digest()
  3. 生成服务密钥:k_service = hmac.new(k_region, "s3".encode(), hashlib.sha256).digest()
  4. 生成签名密钥:k_signing = hmac.new(k_service, "aws4_request".encode(), hashlib.sha256).digest()
  5. 计算最终签名:将步骤2.2生成的待签名字符串用k_signing做HMAC-SHA256哈希,转换为十六进制字符串

将计算得到的签名与URL中的X-Amz-Signature值对比,若完全一致则说明签名真实有效。

4. 额外校验项

  • 检查X-Amz-Date与当前时间的差值,确认URL是否在有效期内(预签名URL默认有效期15分钟,可在生成时自定义)
  • 确认X-Amz-Credential中的Access Key ID是拥有该MRAP对象访问权限的合法密钥
  • (可选)若存在X-Amz-Security-Token,可通过STS API验证临时凭证的有效性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:42:07