请求签名V4

最近更新时间:2019-11-14 12:35:48

使用对象存储服务(KS3) 时,可通过 RESTful API 对 KS3 发起 HTTP 匿名请求或 HTTP 签名请求,对于签名请求,KS3服务器端将会进行对请求发起者的身份验证。

  • 匿名请求:HTTP 请求不携带任何身份标识和鉴权信息,通过 RESTful API 进行 HTTP 请求操作。
  • 签名请求:HTTP 请求时携带签名,KS3服务器端收到消息后,进行身份验证,验证成功则可接受并执行请求,否则将会返回错误信息并丢弃此请求。

KS3 V4签名兼容 AWS Signature Version 4,签名方法见Authenticating Requests - AWS Signature Version 4

注意: 本文所描述的 API 请求签名,如果您使用 SDK 进行开发,SDK中会包含计算方法。仅在您希望通过原始 API 进行二次开发时,需要根据本文所描述步骤进行操作。

V4 签名流程

1. StringToSign计算

1.1 CanonicalRequest计算方法

计算公式

CanonicalRequest = HTTPRequestMethod + '\n'
        + CanonicalURI + '\n'
        + CanonicalQueryString + '\n'
        + CanonicalHeaders + '\n'
        + SignedHeaders + '\n'
        + HexEncode(Sha256Hash(RequestPayload))

说明:

HTTPRequestMethod

首先是 HTTP 请求方法:GET、PUT、POST、DELETE等

CanonicalURI

/[BucketName]/[ObjectKey]

1、对请求资源进行urlencode,'/'不做encode

2、不包含?及后面的queryString

3、urlencode参考URLencode方法;

4、bucketName作为host一部分,文件名字为空时,请求资源为'/'

5、查询bucket 列表接口,请求资源为'/'

CanonicalQueryString

添加规范查询字符串,后跟换行符。

如果请求不包括查询字符串,请使用空字符串填充(实际上是空白行)

要构建规范查询字符串,请完成以下步骤:

  • 按字符代码升序顺序对参数名称进行排序。具有重复名称的参数应按值进行排序。例如,以大写字母 F 开头的参数名称排在以小写字母 b 开头的参数名称之前。

  • 根据以下规则对每个参数名称和值进行 URI 编码。

  • 以排序后的列表中第一个参数名称开头,构造规范查询字符串。

  • 对于每个参数,追加 URI 编码的参数名称,后跟等号字符 (=),再接 URI 编码的参数值。对没有值的参数使用空字符串。

  • 在每个参数值后追加与字符 (&),列表中最后一个值除外。

计算公式如下:

UriEncode("query1")+"="+UriEncode("value1")+"&"+
UriEncode("query2")+"="+UriEncode("value2") + "&" +
...
UriEncode("queryn")+"="+UriEncode("valuen")

CanonicalHeaders

添加规范请求header,每个请求header健值对之间用"\n"进行分割,健值用‘:’连接

构造请求前需要对header进行排序,按照字符升序顺序对header名称进行排序

header名称需要转换为小写字母,value需要做trim

构造公式如下:

Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n"
Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n"
...
Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"

The CanonicalHeaders 列表如下:

  • 必须包含host头

  • 如果请求头有Content-Type,必须添加到CanonicalHeaders

  • 任何以x-kss-开头的请求头,需要添加到CanonicalHeaders中。

  • 临时授权,需要添加x-amz-security-token

  • x-amz-content-sha256是必须的。

  • 除了上述列出的必须增加的头,只计算SignedHeaders中包含的头

  • 注意 Authorization不参与签名内容计算

SignedHeaders

防止用户请求header被篡改,列出参与鉴权运算的鉴权头,列表和CanonicalHeaders 一致,中间用‘;’号进行分割。运算格式为

Lowercase(<HeaderName1>)+";"+Lowercase(<HeaderName2>)+";"+...+Lowercase(<HeaderNameN>)

时间戳(x-amz-date或Date请求头)15分钟内有效,没有权限的用户可通过截获已签名的请求,并篡改SignedHeaders中没有包含的部分,所以建议您签名所有请求头和请求体

x-amz-content-sha256

x-amz-content-sha256 请求头是必须的,取值范围如下:

描述
HexEncode(Sha256Hash(RequestPayload)) 请求正文经过哈希处理的以小写十六进制字符串表示形式
UNSIGNED-PAYLOAD 忽略请求正文的has校验
STREAMING-AWS4-HMAC-SHA256-PAYLOAD chunk传输校验,基于v4的新接口协议,暂不支持

计算方法为

HashedPayload = Lowercase(HexEncode(SHA256Hash(requestPayload)))

使用 SHA256 等哈希 (摘要) 函数以基于 HTTP 或 HTTPS 请求正文中的负载创建哈希值。签名版本 4 不需要您使用特定字符编码来对负载中的文本进行编码。

在创建待签字符串后,请指定用于对负载进行哈希处理的签名算法。例如,如果您使用的是 SHA256,则将指定 AWS4-HMAC-SHA256 作为签名算法。经过哈希处理的负载必须以小写十六进制字符串形式表示。

如果负载为空,则使用空字符串作为哈希函数的输入。

1.2 StringToSign

要创建待签字符串(StringToSign),请如以下伪代码所示,连接算法、日期和时间、凭证范围和规范请求的摘要:

StringToSign结构

StringToSign =
    Algorithm + \n +
    RequestDateTime + \n +
    CredentialScope + \n +
    HashedCanonicalRequest

创建StringToSign

  • 以算法名称开头,后跟换行符。该值是您用于计算规范请求摘要的哈希算法。对于 SHA256,算法是 AWS4-HMAC-SHA256。

  • 追加请求日期值,后跟换行符。该日期是使用 ISO8601 基本格式以 YYYYMMDD'T'HHMMSS'Z' 格式在 x-amz-date(x-kss-data) 标头中指定的。此值必须与您在前面所有步骤中使用的值匹配。

  • 追加凭证范围值,后跟换行符。此值是一个字符串,包含日期、目标区域、所请求的服务和小写字符形式的终止字符串(“kss4_request”)。区域和服务名称字符串必须采用 UTF-8 编码。

date.Format(<YYYYMMDD>) + "/" + <region> + "/" + <service> + "/kss4_request"

日期必须为 YYYYMMDD 格式。请注意,日期不包括时间值。

请确保您指定的区域是您将请求发送到的目标区域。KS3的region 对应关系请参阅Region英文名称

2. SigningKey计算方法

SigningKey: 要对您的消息进行签名,需使用您的AccessKey计算您的签名密钥。为此,请使用您的AccessKey创建一系列基于哈希的消息身份验证代码 (HMAC)。此代码显示在以下伪代码中,其中 HMAC(key, data) 表示以二进制格式返回输出的 HMAC-SHA256 函数。每个哈希函数的结果将成为下一个函数的输入。

用于计算SigningKey的伪代码

kSecret = your Access Key 
kDate = HMAC("KSS4" + kSecret, Date)
kRegion = HMAC(kDate, Region)
kService = HMAC(kRegion, Service)
kSigning = HMAC(kService, "kss4_request")

请注意,哈希过程中所使用的日期的格式为 YYYYMMDD(例如,20150830),不包括时间。

确保以正确的顺序为您要使用的编程语言指定 HMAC 参数。在此示例中,密钥是第一个参数,数据 (消息) 是第二个参数,但您使用的函数可能以不同顺序指定密钥和数据。

使用摘要 (二进制格式) 来派生密钥。大多数语言都有用来计算二进制格式哈希(通常称为摘要)或十六进制编码哈希(称为十六进制摘要)的函数。派生密钥需要使用二进制格式摘要。

以下示例显示了用于计算SigningKey的输入以及所生成的输出,其中 kSecret = wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY。

示例输入:

HMAC(HMAC(HMAC(HMAC("KSS4" + kSecret,"20150830"),"BEIJING"),"ks3"),"kss4_request")

3. signature计算

计算公式为

HMAC-SHA256(SigningKey, StringToSign)

签名使用

通过 RESTful API 对 KS3 发起的 HTTP 签名请求,可以通过以下几种方式传递签名:

  1. 通过标准的 HTTP Authorization 头;

  2. 作为 HTTP QueryString,请注意 UrlEncode;
  3. 签名在表单中;

通过通过标准的 HTTP Authorization 头发送签名请求

签名头格式为

Authorization: algorithm Credential=access key ID/credential scope, SignedHeaders=SignedHeaders, Signature=signature

示例:

PUT /test/uploadfile HTTP/1.1
Host: gzz-test.s3-us-west-2.amazonaws.com
X-Amz-Date: 20190927T100359Z
Authorization: AWS4-HMAC-SHA256 Credential=AKIAIPXSWFJRPW3RWPJ8PK/20190927/us-west-2/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-retry;content-length;content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=6d9df5717ebb7cdeae7d08d817b80d6a90ca32320b07e46f30c64136eade9d48
amz-sdk-retry: 0/0/500
User-Agent: aws-sdk-java/1.11.311 Windows_8.1/6.3 Java_HotSpot(TM)_64-Bit_Server_VM/24.60-b09 java/1.7.0_60
x-amz-content-sha256: f68d27da17d9fd49440b0b8dac130f4f98a2d4c6aca3c9221cdbc8b264b2c8be
amz-sdk-invocation-id: e5d51221-298a-2fc0-3adf-09390a1f5beb
Content-Type: text/plain
Content-Length: 6
Connection: Keep-Alive

通过 URL QueryString 发送签名

示例:

http://ks3-cn-beijing.ksyun.com/54554/hosts.txt?X-Kss-Algorithm=KSS4-HMAC-SHA256&X-Kss-Credential=Vc7A7P4Z6wBy%2BwrOE6ff%2F20191024%2FBEIJING%2Fks3%2Fkss4_request&X-Kss-Date=20191024T065239Z&X-Kss-Expires=900&X-Kss-Signature=865fe37a5562e79aec9da8a7f252987c4c62b29d80adadbed8a699ae877e73f1&X-Kss-SignedHeaders=host

签名在URL QueryString中和在header中计算方法一样,只是签名信息在queryString中。

queryString列表如下

queryString 描述
X-Kss-Algorithm 签名算法:HMAC-SHA256
X-Kss-Credential 签名范围:格式为////kss4_request
X-Kss-Date 请求时间:时间格式为 yyyyMMddTHHmmssZ (X-Kss-Date<=now+15m) 请求的时间戳不能大于(服务器时间戳+15m)
X-Kss-Expires 过期时间,单位秒。时间范围为1-604800(7天)(X-Kss-Date+expire>=now)请求时间戳+过期时间 大于服务器时间戳
X-Kss-SignedHeaders 签名header
X-Kss-Signature 签名结果(计算签名时queryString不包含X-Kss-Signature)

签名在表单中

对于验证的 Post 请求,HTML 表单中必须包含 Policy 和 Signature 信息。 Policy 控制请求中哪些值是允许的。

计算 Signature 的具体流程为:

1)创建一个 UTF-8 编码的 Policy文档,如何构建policy ,详见Policy构建方法

2)将 Policy 进行 base64 编码,其值即为 Policy 表单域中填入的值,将该值作为签名的字符串(StringToSign)。

3)签名Signature =HMAC-SHA256(SigningKey, StringToSign)

表单 说明
policy 表单上传安全策略
X-Kss-Algorithm 签名算法:HMAC-SHA256
X-Kss-Credential 签名范围:格式为////kss4_request
X-Kss-Date 请求时间:时间格式为 yyyyMMddTHHmmssZ (X-Kss-Date<=now+15m) 请求的时间戳不能大于(服务器时间戳+15m)
X-Kss-Signature 签名结果(计算签名时queryString不包含X-Kss-Signature)

其它说明

1. 日期

您在凭证范围中使用的日期必须与您的请求的日期匹配。您可以用多种方法将日期包括在请求中。您可以使用 date 标头或 x-kss-date(x-amz-date) 标头,或者将 x-kss-date(x-amz-date) 作为查询参数包含在内。

时间戳必须采用 UTC 表示,并具有以下 ISO 8601 格式:YYYYMMDD'T'HHMMSS'Z'。例如,20150830T123600Z 是有效时间戳。请勿在时间戳中包含毫秒。

先检查时间戳的x-kss-date(x-amz-date)标头或参数。如果 无法找到 x-kss-date(x-amz-date) 的值,则将寻找 date 标头。 检查八位数字字符串形式的凭证范围,表示请求的年 (YYYY)、月 (MM) 和日 (DD)。例如,如果 x-amz-date 标头值为 20111015T080000Z,并且凭证范围的日期部分为 20111015,则 允许身份验证过程继续执行。

如果日期不匹配,则 拒绝请求,即使时间戳距离凭证范围中的日期仅有数秒之差也是如此。例如,将拒绝其x-kss-date(x-amz-date) 标头值为 20151014T235959Z 且凭证范围包括日期 20151015 的请求。

2. URLencode方法

  • 请勿对 RFC 3986 定义的任何非预留字符进行 URI 编码,这些字符包括:A-Z、a-z、0-9、连字符 (-)、下划线 (_)、句点 (.) 和波形符 (~)。
  • 空格字符必须编码为 %20(不像某些编码方案那样使用“+”)
  • 使用 %XY 对所有其他字符进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F),扩展 UTF-8 字符必须采用格式 %XY%ZA%BC
  • 除了对象名称之外,对前斜杠字符‘/’进行编码

3.协议头

AWS 以x-amz-开头,KS3以x-kss-开头,本协议兼容AWS,同时又支持ks3 v4签名。

- s3 ks3
请求头前缀 x-amz- x-kss-
queryString前缀 X-Amz- X-Kss-
协议 AWS4 KSS4
产品 s3 ks3
定值 aws4_request kss4_request

金山云,开启您的云计算之旅

注册有礼