

# 对请求进行身份验证：使用查询参数（Amazon 签名版本 4）
<a name="sigv4-query-string-auth"></a>

如身份验证概述（请参阅[身份验证方法](sig-v4-authenticating-requests.md#auth-methods-intro)）中所述，您可以使用查询字符串参数提供身份验证信息。当您想要在 URL 中完整表达请求时，使用查询参数对请求进行身份验证很有用。此方法也称为对 URL 进行预签名。

预签名 URL 的一个使用案例场景是，您可以授予对 Amazon S3 资源的临时访问权限。例如，您可以在网站上嵌入预签名 URL，或者在命令行客户端（例如 Curl）中使用它来下载对象。

**注意**  
也可以使用 Amazon CLI 来创建预签名 URL。有关更多信息，请参阅《Amazon CLI Command Reference》**中的 [`presign`](https://docs.amazonaws.cn/cli/latest/reference/s3/presign.html)。

以下是示例预签名 URL。

 

```
https://examplebucket.s3.amazonaws.com/test.txt
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential={{<your-access-key-id>}}/20130721/us-east-1/s3/aws4_request
&X-Amz-Date=20130721T201207Z
&X-Amz-Expires=86400
&X-Amz-SignedHeaders=host
&X-Amz-Signature={{<signature-value>}}
```



在示例 URL 中，注意以下各项：

 
+ 为了便于阅读，添加了换行符。
+ URL 中的 `X-Amz-Credential` 值显示“/”字符只是为了方便阅读。实际上，它应该编码为 `%2F`。例如：

   

  ```
  &X-Amz-Credential={{<your-access-key-id>}}%2F20130721%2Fus-east-1%2Fs3%2Faws4_request
  ```

  

下表介绍了 URL 中提供身份验证信息的查询参数。


| 查询字符串参数名称 | 示例值 | 
| --- | --- | 
| X-Amz-Algorithm | 标识 Amazon 签名版本以及用于计算签名的算法。<br />对于 Amazon 签名版本 4，您可以将此参数值设置为 `AWS4-HMAC-SHA256`。该字符串标识 Amazon 签名版本 4（Amazon4）和 HMAC-SHA256 算法（HMAC-SHA256）。 | 
| X-Amz-Credential | 除了访问密钥 ID 外，该参数还提供签名有效的范围（Amazon Web Services 区域和服务）。该值必须与您在签名计算中使用的范围匹配（后续部分将对此进行说明）。该参数值的一般形式如下：<br /> <pre>{{<your-access-key-id>}}/{{<date>}}/{{<Amazon Web Services 区域>}}/{{<Amazon-service>}}/aws4_request</pre><br />例如：<br /> <pre>AKIAIOSFODNN7EXAMPLE/20130721/us-east-1/s3/aws4_request</pre><br />对于 Amazon S3，{{Amazon-service}} 字符串为 `s3`。有关 S3 `AWS-region` 字符串的列表，请参阅《Amazon Web Services 一般参考》**中的[区域和端点](https://docs.amazonaws.cn/general/latest/gr/rande.html#s3_region)。 | 
| X-Amz-Date | 日期和时间格式必须遵循 ISO 8601 标准，并且必须按照“{{yyyyMMdd}}T{{HHmmss}}Z”格式进行格式化。例如，如果日期和时间是“08/01/2016 15:32:41.982-700”，则必须先将其转换为 UTC（协调世界时），然后以“20160801T223241Z”形式提交。 | 
| X-Amz-Expires | 提供生成的预签名 URL 的有效时间段（以秒为单位）。例如，`86400`（24 小时）。该值是一个整数。您可以设置的最小值为 1，最大值为 604800（七天）。<br />预签名 URL 的有效期最长为七天，因为您在签名计算中使用的签名密钥的有效期最长为七天。 | 
| X-Amz-SignedHeaders | 列出用于计算签名的标头。签名计算中需要以下标头：<br /> +  HTTP `host` 标头。 <br />+  您计划添加到请求的任何 `x-amz-*` 标头。 <br />   为了提高安全性，您应该签署计划在请求中包含的所有请求标头。  | 
| X-Amz-Signature | 提供签名以验证您的请求。该签名必须与 Amazon S3 计算出的签名相匹配；否则 Amazon S3 会拒绝该请求。例如，` 733255ef022bec3f2a8701cd61d4b371f3f28c9f193a1f02279211d48d5193d7`<br />以下部分将介绍签名计算： | 
| X-Amz-Security-Token | 如果使用来自 STS 服务的凭证，则为可选凭证参数。 | 



## 计算签名
<a name="query-string-auth-v4-signing"></a>

下图说明了签名计算过程。

 

![Amazon 签名版本 4 签名流程，包括规范请求、待签字符串和签名生成步骤。](http://docs.amazonaws.cn/AmazonS3/latest/developerguide/images/sigV4-using-query-params.png)




下表介绍了图中显示的函数。您需要为这些函数实现代码。


| 函数 | 说明 | 
| --- | --- | 
| Lowercase() | 将字符串转换为小写。 | 
| Hex() | base-16 编码的小写形式。 | 
| SHA256Hash() | 安全哈希算法（SHA）加密哈希函数。 | 
| HMAC-SHA256() | 使用 SHA256 算法和提供的签名密钥计算 HMAC。这是最终的签名。 | 
| Trim() | 删除所有前导空格或尾随空格。 | 
| UriEncode() | URI 对每个字节进行编码。UriEncode() 必须强制执行以下规则：+  URI 对除非预留字符之外的所有字节进行编码：“A”-“Z”、“a”-“z”、“0”-“9”、“-”、“.”、“\_”和“\~”。 <br />+ 空格字符是预留字符，必须编码为“%20”（而不是“\+”）。<br />+ 每个 URI 编码字节由“%”和该字节的两位十六进制值组成。<br />+ 十六进制值中的字母必须为大写，例如“%1A”。<br />+ 对除对象键名称之外的所有位置的正斜杠字符“/”进行编码。例如，如果对象键名称是 `photos/Jan/sample.jpg`，则不会对键名称中的正斜杠进行编码。 由于底层 RFC 中的实现差异和相关歧义，您开发平台提供的标准 UrienCode 函数可能无法正常工作。建议您编写自己的自定义 UrienCode 函数，以确保编码能够正常工作。 <br />以下是 Java 中的 UriEncode() 函数示例。<pre>public static String UriEncode(CharSequence input, boolean encodeSlash) {<br />          StringBuilder result = new StringBuilder();<br />          for (int i = 0; i < input.length(); i++) {<br />              char ch = input.charAt(i);<br />              if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {<br />                  result.append(ch);<br />              } else if (ch == '/') {<br />                  result.append(encodeSlash ? "%2F" : ch);<br />              } else {<br />                  result.append(toHexUTF8(ch));<br />              }<br />          }<br />          return result.toString();<br />      }</pre> | 

有关签名过程（创建规范请求、待签字符串和签名计算的详细信息）的更多信息，请参阅 [Authorization 标头的签名计算：在单个分块中传输有效载荷（Amazon 签名版本 4）](sig-v4-header-based-auth.md)。除了在预签名 URL 中创建 **CanonicalRequest** 之外，过程大致相同，如下所示：

 
+ 您未在**规范请求**中包含有效载荷哈希值，原因是当您创建预签名 URL 时，您并不知道有效载荷内容，因为该 URL 用于上传任意有效载荷。而应使用常量字符串 `UNSIGNED-PAYLOAD`。
+ **规范查询字符串**必须包含上表中除 `X-Amz-Signature` 之外的所有查询参数。
+ 对于 S3，如果使用源自 STS 服务的凭证，您必须在 URL 中包含 `X-Amz-Security-Token` 查询参数。
+ **规范标头**必须包含 HTTP `host` 标头。如果您计划包含任何 `x-amz-* ` 标头，则还必须添加这些标头以进行签名计算。您可以选择添加您计划在请求中包含的所有其它标头。为了提高安全性，您应该对尽可能多的标头进行签名。如果您添加的已签名标头也是已签名的查询参数，而它们的值不同，则由于输入存在冲突，您将收到 `InvalidRequest` 错误消息。

## 一个示例
<a name="query-string-auth-v4-signing-example"></a>

假设您的 `examplebucket` 存储桶中有一个对象 `test.txt`。您希望通过创建预签名 URL 与他人共享此对象达 24 小时（86400 秒）。

 

```
https://examplebucket.s3.amazonaws.com/test.txt
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request
&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
&X-Amz-Signature={{<signature-value>}}
```

以下步骤首先说明签名计算，然后说明预签名 URL 的构造。该示例作出以下附加假设：

 
+ 请求时间戳为 `Fri, 24 May 2013 00:00:00 GMT`。
+ 存储桶位于美国东部（弗吉尼亚州北部）区域，凭证 `Scope` 和 `Signing Key` 计算使用 `us-east-1` 作为区域说明符。有关更多信息，请参阅 [https://docs.amazonaws.cn/general/latest/gr/rande.html#s3_region](https://docs.amazonaws.cn/general/latest/gr/rande.html#s3_region)* 中的Amazon Web Services 一般参考区域和终端节点*。

您可以将此示例用作测试用例来验证您的代码计算的签名；但是，您必须使用相同的存储桶名称、对象键、时间戳和以下示例凭证：


| 参数 | 值 | 
| --- | --- | 
| AWSAccessKeyId | AKIAIOSFODNN7EXAMPLE | 
| AWSSecretAccessKey | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY | 

1. 

**StringToSign**

   1. 

**CanonicalRequest**

       

      ```
      GET
      /test.txt
      X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
      host:examplebucket.s3.amazonaws.com
      
      host
      UNSIGNED-PAYLOAD
      ```

       

   1. 

**StringToSign**

       

      ```
      AWS4-HMAC-SHA256
      20130524T000000Z
      20130524/us-east-1/s3/aws4_request
      3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04
      ```

       

1. 

**SigningKey**

    

   ```
   signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "{{<YourSecretAccessKey>}}","20130524"),"us-east-1"),"s3"),"aws4_request")
   ```

    

1. 

**Signature**

    

   ```
   aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404
   ```

    

   现在，您已经掌握了构造预签名 URL 的所有信息。此示例生成的 URL 如下所示（您可以使用它来比较您的预签名 URL）：

   ```
   https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404
   ```

## 示例 2
<a name="query-string-auth-v4-signing-example-2"></a>

以下是一个显示带有 `X-Amz-Security-Token` 参数的预签名 URL 的示例（与前一个示例无关）。

```
https://examplebucket.s3.us-east-1.amazonaws.com/test.txt
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request
&X-Amz-Date=20200524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEMv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJGMEQCIBSUbVdj9YGs2g0HkHsOHFdkwOozjARSKHL987NhhOC8AiBPepRU1obMvIbGU0T%2BWphFPgK%2Fqpxaf5Snvm5M57XFkCqlAgjz%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDQ3MjM4NTU0NDY2MCIM83pULBe5%2F%2BNm1GZBKvkBVslSaJVgwSef7SsoZCJlfJ56weYl3QCwEGr2F4BmCZZyFpmWEYzWnhNK1AnHMj5nkfKlKBx30XAT5PZGVrmq4Vkn9ewlXQy1Iu3QJRi9Tdod8Ef9%2FyajTaUGh76%2BF5u5a4O115jwultOQiKomVwO318CO4l8lv%2F3HhMOkpdanMXn%2B4PY8lvM8RgnzSu90jOUpGXEOAo%2F6G8OqlMim3%2BZmaQmasn4VYRvESEd7O72QGZ3%2BvDnDVnss0lSYjlv8PP7IujnvhZRnj0WoeOyMe1lL0wTG%2Fa9usH5hE52w%2FYUJccOn0OaZuyROuVsRV4Q70sbWQhUvYUt%2B0tUMKzm8vsFOp4BaNZFqobbjtb36Y92v%2Bx5kY6i0s8QE886jJtUWMP5ldMziClGx3p0mN5dzsYlM3GyiJ%2FO1mWkPQDwg3mtSpOA9oeeuAMPTA7qMqy9RNuTKBDSx9EW27wvPzBum3SJhEfxv48euadKgrIX3Z79ruQFSQOc9LUrDjR%2B4SoWAJqK%2BGX8Q3vPSjsLxhqhEMWd6U4TXcM7ku3gxMbzqfT8NDg%3D
&X-Amz-Signature={{<signature-value>}}
```