服务端签名后直传 服务端签名直传并设置上传回调
服务端签名后直传_Web端直传实践_最佳实践_对象存储 OSS-阿里云 https://help.aliyun.com/document_detail/31926.html
服务端签名直传并设置上传回调_Web端直传实践_最佳实践_对象存储 OSS-阿里云 https://help.aliyun.com/document_detail/31927.html
https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/RESTAuthentication.html
主题
注意
本主题说明使用签名版本 2 对请求进行身份验证。Amazon S3 现在支持最新的签名版本 4。所有区域都支持此最新签名版本,而 2014 年 1 月 30 日之后的所有新区域都只支持签名版本 4。有关更多信息,请参阅 Amazon Simple Storage Service API Reference 中的对请求进行身份验证(AWS 签名版本 4)。
身份验证是指向系统证明身份的过程。身份对于 Amazon S3 访问控制决策非常重要。将根据请求者的身份允许请求或拒绝部分请求。例如,将为已注册的开发人员保留创建存储桶的权利,并且 (默认) 将为相关的存储桶拥有者保留在存储桶中创建对象的权利。作为开发人员,您需要创建请求来调用这些权限,因此您需要对您的请求进行身份验证以向系统证明您的身份。本节向您演示了应如何进行操作。
注意
本节中的内容不适用于 HTTP POST。有关更多信息,请参阅 使用 POST(AWS 签名版本 2)的基于浏览器的上传。
Amazon S3 REST API 使用基于密钥 HMAC (Hash Message Authentication Code) 的自定义 HTTP 方案进行身份验证。要对请求进行身份验证,您首先需要合并请求的选定元素以形成一个字符串。然后,您可以使用 AWS 秘密访问密钥来计算该字符串的 HMAC。通常我们将此过程称为“签署请求”并且我们将输出 HMAC 算法称为“签名”,因为它会模拟真实签名的安全属性。最后,您可以使用本部分中介绍的语法,作为请求的参数添加此签名。
系统收到经身份验证的请求时,将提取您申领的 AWS 秘密访问密钥,并以相同的使用方式将它用于计算已收到的消息的签名。然后,它会将计算出的签名与请求者提供的签名进行对比。如果两个签名相匹配,则系统认为请求者必须拥有对 AWS 秘密访问密钥的访问权限,因此充当向其颁发密钥的委托人的颁发机构。如果两个签名不匹配,那么请求将被丢弃,同时系统将返回错误消息。
例 经身份验证的 Amazon S3 REST 请求
GET /photos/puppy.jpg HTTP/1.1
Host: johnsmith.s3.amazonaws.com
Date: Mon, 26 Mar 2007 19:37:58 +0000
Authorization: AWS AKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCwo//yllqDzg=
使用临时安全凭证
如果您使用临时安全凭证签署请求 (参阅 创建请求),您必须通过添加 x-amz-security-token
标头将相应的安全令牌包含在您的请求中。
使用 AWS Security Token Service API 获取临时安全凭证时,响应包含临时安全凭证和会话令牌。向 Amazon S3 发送请求时,您可以在 x-amz-security-token
标头中提供会话令牌值。有关 IAM 提供的 AWS Security Token Service API 的信息,请转到 AWS Security Token Service API Reference 指南 中的操作。
身份验证标头
Amazon S3 REST API 使用标准的 HTTP Authorization
标头来传递身份验证信息。(标准标头的名称是不可取的,因为它承载的是身份验证信息,而不是授权。) 在 Amazon S3 身份验证方案下,授权标头具有以下形式:
Authorization: AWS AWSAccessKeyId
:Signature
注册后,会向开发人员颁发 AWS 访问密钥 ID 和 AWS 秘密访问密钥。对于请求身份验证,AWSAccessKeyId
元素将标识用于计算签名的访问密钥 ID 和进行请求的开发人员 (间接)。
Signature
元素是请求中选定元素的 RFC 2104HMAC-SHA1,因此授权标头的 Signature
部分会因请求的不同而各异。如果系统计算出的请求签名与请求随附的 Signature
相匹配,则请求者证明拥有 AWS 秘密访问密钥。然后,在该身份下,借助获得此密钥的开发人员的授权来处理请求。
以下是说明 Authorization
请求标头结构的伪语法。(在该示例中,\n
表示 Unicode 码位 U+000A
,这通常称为换行符)。
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
Signature = Base64( HMAC-SHA1( YourSecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) );
StringToSign = HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource;
CanonicalizedResource = [ "/" + Bucket ] +
<HTTP-Request-URI, from the protocol name up to the query string> +
[ subresource, if present. For example "?acl", "?location", "?logging", or "?torrent"];
CanonicalizedAmzHeaders = <described below>
HMAC-SHA1 是由 RFC 2104(用于消息身份验证的哈希密钥)定义的算法。该算法要求输入两个字节字符串:一个密钥和一个消息。对于 Amazon S3 请求身份验证,请将您的 AWS 秘密访问密钥 (YourSecretAccessKey
) 作为密钥,并将 UTF-8 编码格式的 StringToSign
作为消息。HMAC-SHA1 的输出也是字节字符串,称为摘要。通过对此摘要进行 Base64 编码来构成 Signature
请求参数。
用于签名的请求规范
在系统收到经身份验证的请求时撤销,系统会将计算出的请求签名与 StringToSign
中提供的签名进行对比。基于此原因,您必须采用 Amazon S3 使用的相同方法计算签名。根据适用于签名的统一格式放置请求的过程称为标准化。
构建 CanonicalizedResource 元素
CanonicalizedResource
表示请求的目标 Amazon S3 资源。为 REST 请求构建它,如下所示:
启动过程
1 |
使用空字符串 ( |
2 |
如果请求使用 HTTP 主机标头 (虚拟托管类型) 来指定请求,请在 对于虚拟托管类型请求“https://johnsmith.s3.amazonaws.com/photos/puppy.jpg”, 对于路径类型请求“https://s3.amazonaws.com/johnsmith/photos/puppy.jpg”, |
3 |
附加未解码的 HTTP 请求-URI 的路径部分 (取决于但不包括查询字符串)。 对于虚拟托管类型请求“https://johnsmith.s3.amazonaws.com/photos/puppy.jpg”, 对于路径类型请求“https://s3.amazonaws.com/johnsmith/photos/puppy.jpg”, 对于不寻址存储桶的请求 (例如,GET Service),请附加“/”。 |
4 |
如果请求将寻址子资源 (例如, 构建 CanonicalizedResource 元素时必须包含的子资源为:acl、lifecycle、location、logging、notification、partNumber、policy、requestPayment、torrent、uploadId、uploads、versionId、versioning、versions 和 website。 如果请求指定覆盖响应标头值的查询字符串参数(请参阅 Get Object),请附加查询字符串参数及其值。签名时,请勿对这些值进行编码;但是进行请求时,您必须对这些参数值进行编码。GET 请求中的查询字符串参数包括 为多对象删除请求创建 CanonicalizedResource 时,必须包括 |
必须按照元素在 HTTP 请求中的显示方式,使用字母 (包括 URL 编码元字符) 签署来自 HTTP 请求-URI 的 CanonicalizedResource 元素。
CanonicalizedResource
可能与 HTTP 请求-URI 不同。尤其是,如果您的请求使用 HTTP Host
标头来指定存储桶,存储桶不会在 HTTP 请求 URI 中显示。但是,CanonicalizedResource
仍然会包含该存储桶。查询字符串参数可能也会在请求-URI 中显示,但是不会包括在 CanonicalizedResource
中。有关更多信息,请参阅 存储桶的虚拟托管。
构建 CanonicalizedAmzHeaders 元素
要构建 StringToSign
的 CanonicalizedAmzHeaders 部分,请选择所有以“x-amz-”开头的 HTTP 请求标头 (使用不区分大小写的对比方式) 并遵循以下步骤。
CanonicalizedAmzHeaders 步骤
1 | 将每个 HTTP 标头名称转换为小写。例如,“X-Amz-Date ”改为“x-amz-date ”。 |
2 | 根据标头名称按字典顺序排列标头集。 |
3 | 按照 RFC 2616 中第 4.2 节中的规定,将相同名称的标头字段合并为一个“header-name:comma-separated-value-list”对,各值之间不留空格。例如,可以将元数据标头“x-amz-meta-username: fred ”和“x-amz-meta-username: barney ”合并为单个标头“x-amz-meta-username: fred,barney ”。 |
4 | 通过将折叠空格 (包括换行符) 替换为单个空格,“展开”跨多个行的长标头 (按照 RFC 2616 中第 4.2 节允许的方式)。 |
5 | 删除标头中冒号周围的空格。例如,标头“x-amz-meta-username: fred,barney ”改为“x-amz-meta-username:fred,barney ”。 |
6 | 最后,请向生成的列表中的每个标准化标头附加换行字符 (U+000A )。通过将此列表中所有的标头规范化为单个字符串,构建 CanonicalizedResource 元素。 |
位置和命名 HTTP 标头 StringToSign 元素的对比
StringToSign
的头几个标头元素(Content-Type、Date 和 Content-MD5)属于位置标头。StringToSign
不包括这些标头的名称,仅包括它们在请求中的值。相反,“x-amz-
”元素会进行命名。标头名称和标头值都会在 StringToSign
中显示。
如果在 StringToSign
定义中调用的位置标头不在请求中 (例如,Content-Type
或 Content-MD5
对于 PUT 请求是可选的,并且对于 GET 请求没有任何意义),请使用空字符串 ("") 替换该位置。
时间戳要求
有效的时间戳对于经身份验证的请求是必须的 (使用 HTTP Date
标头或 x-amz-date
替代项)。此外,经身份验证的请求随附的客户端时间戳必须处于收到请求时的 Amazon S3 系统时间的 15 分钟之内。否则,请求将失败并出现 RequestTimeTooSkewed
错误代码。施加这些限制的目的是为了防止对方重新使用已拦截的请求。要更好地防范窃听,请对经身份验证的请求使用 HTTPS 传输。
注意
对请求日期的验证限制仅适用于不使用查询字符串身份验证的经身份验证的请求。有关更多信息,请参阅 查询字符串请求身份验证替代项。
某些 HTTP 客户端库不提供为请求设置 Date
标头的功能。如果您在标准化标头中包含“Date”标头的值时遇到困难,您可以改用“x-amz-date
”标头为请求设置时间戳。x-amz-date
标头的值必须采用 RFC 2616 格式 (http://www.ietf.org/rfc/rfc2616.txt) 中的任意格式。x-amz-date
标头位于请求中时,系统将在计算请求签名时忽略任何 Date
标头。因此,如果包含了 x-amz-date
标头,请在构建 Date
时使用 StringToSign
的空字符串。有关示例,请参阅下一节。
身份验证示例
本节中的示例使用下表中的 (非有效) 凭证。
参数 | 值 |
---|---|
AWSAccessKeyId | AKIAIOSFODNN7EXAMPLE |
AWSSecretAccessKey | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
在示例 StringToSign
中,格式并不重要;\n
是指 Unicode 码位 U+000A
,通常称为换行符。此外,该示例使用“+0000”指定时区。您可以改用“GMT”来指定时区,但是在示例中显示的签名将有所不同。
对象 GET
本示例将从 johnsmith 存储桶获取一个对象。
请求 | StringToSign |
---|---|
|
|
请注意,CanonicalizedResource 包括存储桶名称,但 HTTP 请求 URI 不包括。(存储桶由主机标头指定)。
对象 PUT
本示例将对象放置在 johnsmith 存储桶中。
请求 | StringToSign |
---|---|
|
|
请注意请求和 StringToSign 中的 Content-Type 标头。另请注意,由于 Content-MD5 不在请求中,它在 StringToSign 中将保留为空白。
List
本示例列出了 johnsmith 存储桶中的内容。
请求 | StringToSign |
---|---|
|
|
请注意 CanonicalizedResource 上的尾部斜杠以及查询字符串参数的缺失。
取回
本示例将为“johnsmith”存储桶提取访问控制策略子资源。
请求 | StringToSign |
---|---|
|
|
请注意子资源查询字符串参数包含在 CanonicalizedResource 中的方式。
Delete
本示例使用路径类型和日期替代项从“johnsmith”存储桶删除对象。
请求 | StringToSign |
---|---|
|
|
请注意我们如何使用“x-amz-date”替代方法来指定日期 (假设是因为我们的客户端库阻止我们设置日期)。在这种情况下,x-amz-date
优先于 Date
标头。因此,签名中的日期条目必须包含 x-amz-date
标头的值。
上传
本示例将对象上传到使用元数据的别名记录虚拟托管类型存储桶。
请求 | StringToSign |
---|---|
|
|
请注意对“x-amz-”标头排序、删减空格和转换为小写的方式。另请注意,具有相同名称的多个标头使用逗号连接,以分隔值。
请注意,如何仅使 Content-Type
和 Content-MD5
HTTP 实体标头显示在 StringToSign
中。其他 Content-*
实体标头不显示。
同样请注意,CanonicalizedResource
包括存储桶名称,但 HTTP 请求 URI 不包括。(存储桶由主机标头指定)。
列出我的所有存储桶
请求 | StringToSign |
---|---|
|
|
Unicode 密钥
请求 | StringToSign |
---|---|
|
|
注意
将逐字读取来自请求-URI 的 StringToSign
中的元素,包括 URL 编码和大写。
REST 请求签名问题
REST 请求身份验证失败后,系统将使用 XML 错误文档对请求做出响应。此错误文档中包含的信息将帮助开发人员诊断问题。特别是,StringToSign
错误文档的 SignatureDoesNotMatch
元素将明确告诉您系统使用的请求规范。
某些工具包可能会在您事先不知情的情况下自动插入标头,例如在 PUT 操作期间添加标头 Content-Type
。在大部分情况下,插入标头的值保持不变,从而使您可以使用诸如 Ethereal 或 tcpmon 等工具来发现丢失的标头。
查询字符串请求身份验证替代项
您可以通过传递请求信息作为查询字符串参数,而不是使用 Authorization
HTTP 标头来验证特定类型的请求。这在允许第三方浏览器直接访问您的私有 Amazon S3 数据,而无需代理请求时非常有用。其概念是构建一个“预签名”的请求并将其编码为最终用户浏览器可检索的 URL。此外,您还可以通过指定过期时间来限制预签名请求。
注意
有关使用 AWS 开发工具包生成预签名 URL 的示例,请参阅与其他用户共享对象。
创建签名
以下是查询字符串验证的 Amazon S3 REST 请求示例。
GET /photos/puppy.jpg
?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D HTTP/1.1
Host: johnsmith.s3.amazonaws.com
Date: Mon, 26 Mar 2007 19:37:58 +0000
查询字符串请求身份验证方法不要求任何特殊的 HTTP 标头,而是将要求的身份验证元素指定为查询字符串参数:
查询字符串参数名称 | 示例值 | 描述 |
---|---|---|
AWSAccessKeyId |
AKIAIOSFODNN7EXAMPLE |
您的 AWS 访问密钥 ID。指定用于签署请求的 AWS 秘密访问密钥以及 (间接) 进行请求的开发人员的身份。 |
Expires |
1141889120 |
将签名过期时间指定为自 Epoch (1970 年 1 月 1 日 00:00:00 UTC) 以来的秒数。将拒绝在此时间 (根据服务器) 之后收到的请求。 |
Signature |
vjbyPxybdZaNmGa%2ByT272YEAiv4%3D |
采用 StringToSign 的 HMAC-SHA1 Base64 编码的 URL 编码。 |
查询字符串请求身份验证方法与普通的方法稍有差异,不同之处仅在于 Signature
请求参数和 StringToSign
元素的格式。下面的伪语法演示了查询字符串请求身份验证方法。
Signature = URL-Encode( Base64( HMAC-SHA1( YourSecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) ) );
StringToSign = HTTP-VERB + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Expires + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource;
YourSecretAccessKey
是在您注册成为 Amazon Web Service 开发人员时,Amazon 分配给您的 AWS 秘密访问密钥 ID。请注意如何对 Signature
进行 URL 编码,以使其适合放置在查询字符串中。另请注意,在 StringToSign
中,HTTP Date
位置元素已替换为 Expires
。CanonicalizedAmzHeaders
和 CanonicalizedResource
是相同的。
注意
在查询字符串身份验证方法中,在计算要签署的字符串时,请勿使用 Date
或 x-amz-date request
标头。
查询字符串请求身份验证
请求 | StringToSign |
---|---|
|
|
我们假设,在浏览器创建 GET 请求时,它没有提供 Content-MD5 或 Content-Type 标头,也没有设置任何 x-amz- 标头,因此 StringToSign
的这些部分都保留为空白。
使用 Base64 编码
必须使用 Base64 编码 HMAC 请求签名。Base64 编码将签名转换为可附加到请求的简单 ASCII 字符串。如果要在 URI 中使用诸如加号 (+)、正斜杠 (/) 和等号 (=) 等可在签名中显示的字符,必须对它们进行编码。例如,如果身份验证代码包括一个加号 (+) 标志,请在请求中将其编码为 %2B。将正斜杠编码为 %2F,并将等号编码为 %3D。
有关 Base64 编码的示例,请参考 Amazon S3 身份验证示例。