

# 排查 AWS API 请求的签名版本 4 签名问题
<a name="reference_sigv-troubleshooting"></a>

**重要**  
除非您使用 AWS SDK 或 CLI，否则您必须编写代码来计算在请求中提供身份验证信息的签名。SigV4 签名计算可能十分复杂，我们建议您尽可能使用 AWS SDK 或 CLI。

在开发可创建已签名请求的代码时，您可能会从 AWS 服务收到 HTTP 403 `SignatureDoesNotMatch` 错误。此类错误表示您对 AWS 发出的 HTTP 请求中的签名值与 AWS 服务 计算出的签名不一致。当权限不允许调用者发出请求时，系统会返回 HTTP 401 `Unauthorized` 错误。

出现以下情况时，API 请求可能会返回错误：
+ API 请求未签名，并且 API 请求使用的是 IAM 身份验证。
+ 用于签署请求的 IAM 证书不正确或无权调用该 API。
+ 已签名 API 请求的签名与 AWS 服务计算出的签名不一致。
+ API 请求标头不正确。

**注意**  
请首先将签名协议从 AWS 签名版本 2（SigV2）更新为 AWS 签名版本 4（SigV4），然后再探索其他错误解决方案。Amazon S3 等服务和区域不再支持 Sigv2 签名。

**Topics**
+ [凭证错误](#signature-v4-troubleshooting-credential)
+ [规范请求和签名字符串错误](#signature-v4-troubleshooting-canonical-errors)
+ [凭证范围错误](#signature-v4-troubleshooting-credential-scope)
+ [密钥签名错误](#signature-v4-troubleshooting-key-signing)

## 凭证错误
<a name="signature-v4-troubleshooting-credential"></a>

确保 API 请求是使用 Sigv4 签署的。如果 API 请求未签名，则可能会收到以下错误消息：`Missing Authentication Token`。[添加缺失的签名](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html#add-signature-to-request) 并重新发送请求。

确认访问密钥和私有密钥的身份验证凭证准确无误。如果访问密钥不正确，则可能会收到以下错误消息：`Unauthorized`。确保用于签署请求的实体有权提出请求。有关更多信息，请参阅 [排查访问被拒绝错误消息](troubleshoot_access-denied.md)。

## 规范请求和签名字符串错误
<a name="signature-v4-troubleshooting-canonical-errors"></a>

如果您在 [创建规范请求的哈希值](reference_sigv-create-signed-request.md#create-canonical-request-hash) 或 [创建待签字符串](reference_sigv-create-signed-request.md#create-string-to-sign) 中计算的规范请求有误，则服务执行的签名验证步骤将会失败，并显示以下错误消息：

```
The request signature we calculated does not match the signature you provided
```

AWS 服务收到已签名的请求后，将会重新计算签名。如果两者的值存在差异，则签名不一致。将已签名请求的规范请求和字符串与错误消息中的值进行比较。如果两者有任何差异，请修改签名过程。

**注意**  
您还可以验证您没有通过修改标头或请求的代理发送请求。

**Example 规范请求示例**  

```
GET                                                      -------- HTTP method
/                                                        -------- Path. For API stage endpoint, it should be /{stage-name}/{resource-path}
                                                         -------- Query string key-value pair. Leave it blank if the request doesn't have a query string.
content-type:application/json                            -------- Header key-value pair. One header per line.
host:0123456789.execute-api.us-east-1.amazonaws.com      -------- Host and x-amz-date are required headers for all signed requests.                       
x-amz-date:20220806T024003Z                              

content-type;host;x-amz-date                             -------- A list of signed headers
d167e99c53f15b0c105101d468ae35a3dc9187839ca081095e340f3649a04501        -------- Hash of the payload
```

要验证密钥是否与访问密钥 ID 匹配，您可以使用已知的有效实施对其进行测试。例如，使用 AWS SDK 或 AWS CLI 向 AWS 发出请求。

### API 请求标头
<a name="signature-v4-troubleshooting-credential-header"></a>

当授权标头为空，凭证密钥或签名缺失或不正确，标头不是以算法名称开头，或者键值对不包含等号时，您会收到以下错误之一：
+ 授权标头不能为空。
+ 授权标头需要“Credential”参数。
+ 授权标头需要“Signature”参数。
+ 签名在授权标头中包含无效的 key=value 对（缺少等号）。

请确保您在 [计算签名](reference_sigv-create-signed-request.md#calculate-signature) 中添加的 SigV4 授权标头包含正确的凭证密钥，同时包含使用 HTTP 日期或 `x-amz-date` 标头的请求日期。

如果您收到 IncompleteSignatureException 错误且签名的构造正确，则可以通过计算客户端请求中授权标头的 SHA-256 哈希值和 B64 编码来验证授权标头在传输到 AWS 服务 的过程中未被修改。

1. 获取您在请求中发送的[授权标头](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-authentication-methods.html)。您的授权标头与以下示例类似：

   ```
   Authorization: AWS4-HMAC-SHA256 
   Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, 
   SignedHeaders=host;range;x-amz-date,
   Signature=example-generated-signature
   ```

1. 计算授权标头的 SHA-256 哈希值。

   ```
   hashSHA256(rawAuthorizationHeader) = hashedAuthorizationHeader
   ```

1. 将经过哈希处理的授权标头编码为 Base64 格式。

   ```
   base64(hashedAuthorizationHeader) = encodedHashedAuthorizationHeader
   ```

1. 将刚才计算的经过哈希处理和编码的字符串与您在错误消息中收到的字符串进行比较。您的错误消息应类似于以下示例：

   ```
   com.amazon.coral.service#IncompleteSignatureException: 
   The signature contains an in-valid key=value pair (missing equal-sign) 
   in Authorization header (hashed with SHA-256 and encoded with Base64): 
   '9c574f83b4b950926da4a99c2b43418b3db8d97d571b5e18dd0e4f3c3ed1ed2c'.
   ```
+ 如果两个哈希值不同，则授权标头的某些部分在传输过程中更改。此更改可能是由于您的网络或客户端处理程序附加签名的标头或以某种方式更改授权标头。
+ 如果两个哈希值匹配，则您在请求中发送的授权标头与 AWS 收到的内容相匹配。查看您收到的错误消息，确定问题是否是凭证或签名不正确的结果。本页面的其他部分将介绍这些错误。

## 凭证范围错误
<a name="signature-v4-troubleshooting-credential-scope"></a>

您在 [创建待签字符串](reference_sigv-create-signed-request.md#create-string-to-sign) 中创建的凭证范围可将签名限定为特定的日期、区域和服务。此字符串具有以下格式：

```
YYYYMMDD/region/service/aws4_request
```

**注意**  
如果您使用的是 Sigv4a，则该区域未包括在凭证范围内。

**日期**  
如果凭证范围未指定与 x-amz-date 标头相同的日期，则签名验证步骤将失败，并显示以下错误消息：

```
Date in Credential scope does not match YYYYMMDD from ISO-8601 version of date from HTTP
```

如果请求指定了未来时间，则签名验证步骤将失败，并显示以下错误消息：

```
Signature not yet current: date is still later than date
```

如果请求已过期，则签名验证步骤将失败，并显示以下错误消息：

```
Signature expired: date is now earlier than date
```

**区域**  
如果凭证范围未指定与请求相同的区域，则签名验证步骤将失败，并显示以下错误消息：

```
Credential should be scoped to a valid Region, not region-code
```

**服务**  
如果凭证范围未指定与 host 标头相同的服务，则签名验证步骤将失败，并显示以下错误消息：

```
Credential should be scoped to correct service: 'service'
```

**终止字符串**  
如果凭证范围没有以 aws4\$1request 结尾，则签名验证步骤将失败，并显示以下错误消息：

```
Credential should be scoped with a valid terminator: 'aws4_request'
```

## 密钥签名错误
<a name="signature-v4-troubleshooting-key-signing"></a>

由于不正确地派生签名密钥或使用密码术而导致的错误更难排查。验证规范字符串和待签字符串正确无误后，还可以检查是否存在以下某个问题：
+ 秘密访问密钥与您指定的访问密钥 ID 不匹配。
+ 您的密钥派生代码存在问题。

要验证密钥是否与访问密钥 ID 匹配，您可以使用已知的有效实施对其进行测试。例如，使用 AWS SDK 或 AWS CLI 向 AWS 发出请求。有关示例，请参阅[请求签名示例](reference_sigv-examples.md)。