AWS 签名版本 4 (SigV4) 是如何工作的 - API 认证的密码学机制
从密码学角度解析 AWS API 认证使用的 SigV4 签名过程的 4 个步骤 (创建规范请求、构建签名字符串、派生签名密钥、计算签名),还介绍 SigV4A 和预签名 URL 的机制。
为什么需要签名
AWS API 的请求需要证明发送者是合法 AWS 用户的认证信息。最简单的认证方式是将访问密钥和秘密密钥直接包含在请求中,但这很危险。请求被截获时秘密密钥会泄露。SigV4 是不将秘密密钥包含在请求中即可进行认证的签名方式。用秘密密钥从请求内容计算签名 (HMAC-SHA256 哈希),将该签名包含在请求中。AWS 侧用相同秘密密钥进行相同计算,签名匹配则认证成功。秘密密钥本身不在网络上传输。此外,SigV4 的签名包含请求内容 (HTTP 方法、URL、头部、正文) 进行计算,请求被篡改时签名不会匹配。这同时保证了认证和完整性。
签名过程的 4 个步骤
SigV4 的签名过程由 4 个步骤构成。步骤 1 是创建规范请求 (Canonical Request)。将 HTTP 方法、URL 路径、查询字符串、头部、正文哈希以特定格式连接成字符串。头部按键字母顺序排序,去除值前后的空格。这种规范化确保相同请求始终生成相同的规范请求。步骤 2 是构建签名字符串 (String to Sign)。连接算法名 (AWS4-HMAC-SHA256)、时间戳、凭证范围 (日期/区域/服务/aws4_request)、规范请求的 SHA-256 哈希。步骤 3 是派生签名密钥。从秘密密钥依次用日期、区域、服务名进行 HMAC-SHA256 叠加生成签名密钥。步骤 4 是计算签名。用签名密钥计算签名字符串的 HMAC-SHA256,转换为十六进制字符串。将此签名包含在 Authorization 头部中发送请求。
签名密钥的派生 - 为什么是多阶段 HMAC
签名密钥的派生通过从秘密密钥经过 4 阶段 HMAC-SHA256 进行。kDate = HMAC(AWS4 + SecretKey, Date)、kRegion = HMAC(kDate, Region)、kService = HMAC(kRegion, Service)、kSigning = HMAC(kService, aws4_request)。这种多阶段派生有两个目的。第一,限定签名的范围。签名密钥绑定日期、区域、服务,某天东京区域 S3 用的签名密钥不能用于其他日期、其他区域或其他服务。签名密钥泄露时损害也被限定。第二,可以缓存签名密钥。同一天、同一区域、同一服务的请求签名密钥相同。SDK 缓存签名密钥,日期变更前可重复使用。无需每次从秘密密钥派生签名密钥,性能提升。签名中包含的时间戳与 AWS 服务器时间差超过 5 分钟会被拒绝。这可防止旧签名的重用 (重放攻击)。
预签名 URL - 将签名嵌入 URL
S3 的预签名 URL 是将 SigV4 签名嵌入查询字符串的 URL。知道这个 URL 的人无需 AWS 认证信息即可访问 S3 对象。预签名 URL 有有效期,最长 7 天 (IAM 用户访问密钥) 或最长 12 小时 (STS 临时认证信息)。预签名 URL 的查询字符串包含 X-Amz-Algorithm (签名算法)、X-Amz-Credential (访问密钥 ID 和凭证范围)、X-Amz-Date (时间戳)、X-Amz-Expires (有效期秒数)、X-Amz-SignedHeaders (签名中包含的头部)、X-Amz-Signature (签名)。预签名 URL 的重要特性是,不是在生成 URL 时的权限下评估,而是在使用 URL 时的权限下评估。生成 URL 后访问密钥被禁用或 IAM 策略被变更时,URL 将无法使用。
SigV4A - 支持多区域的新签名方式
SigV4 的签名密钥绑定区域,因此一个签名无法向多个区域发送请求。像 S3 多区域访问点这样请求可能路由到多个区域的情况,SigV4 无法应对。SigV4A (Signature Version 4A) 是为解决这一限制而引入的扩展。SigV4A 使用 ECDSA (椭圆曲线数字签名算法) 代替 HMAC-SHA256。ECDSA 是非对称密码,签名密钥派生无需包含区域。一个签名可向多个区域发送请求。SigV4A 目前用于 S3 多区域访问点和 EventBridge 全局端点。SDK 根据目标服务和端点自动切换 SigV4 和 SigV4A,开发者几乎无需意识签名方式。要系统学习 AWS 的 API 认证,可参考相关专业书籍 (Amazon)。