签名
网易云基础服务支持 2 中签名方式,所需要的公共参数是不同的,用户可以根据实际情况选择使用哪种签名认证方式。
签名 1
签名流程
1. 在原始请求的基础上添加公共请求参数(Signature 参数除外,Signature 参数需要在签名计算完成后添加)。
2. 构造标准查询字符串 CanonicalizedQueryString
- 2.1 将所有 QueryString 部分参数的 key/value 都分别使用 UTF-8 字符集进行 URL 编码。
- 2.2 将 2.1 处理后的参数按照字典序进行排序。
- 2.3 将 2.2 处理后的参数 key/value 使用 = 连接,不同请求参数之间使用 & 连接。
3. 计算 HashedPayload。
使用 SHA256 哈希算法对 HTTPS 请求正文中的负载(RequestBody)创建哈希值,若负载为空,则使用空字符串参数计算。伪代码如下:
HashedPayload = Lowercase(HexEncode(Hash(RequestPayload)))
4. 计算 String2Sign。
伪代码如下:(其中 \n 为换行符)
String2Sign = HTTPMethod + '\n' + host + '\n' + '/servicename' + '\n' + CanonicalizedQueryString + '\n' + HashedPayload
5. 计算签名。
使用 HMAC-SHA256 协议创建基于哈希的消息身份验证代码 (HMAC),然后计算签名,所得签名进行 Base-64 编码。
6.请求中添加签名。
将 Signature 参数添加到请求参数中,并且和其他请求参数一样也需要进行 URLEncode 。
计算 String2Sign 过程中进行 URL 编码与一般采用application/x-www-form-urlencode MIME 格式编码算法有如下的差异:
字符 | application/x-www-form-urlencode MIME 格式编码结果 | UTF-8 字符集进行 URL 编码结果 |
---|---|---|
空格 | + | %20 |
* | 不编码 | %2A |
~ | %7E | 不编码 |
Attention
1.0 版本签名,所有的公共请求参数都需要放在 QueryString 部分。 在第 2 步中的对参数使用 UTF-8 字符集进行 URL 编码时,需要注意的是这里使用的编码方式和一般采用application/x-www-form-urlencode MIME 格式编码算法有所差异,具体的编码算法参见 RFC 3986 在计算签名时,host 需要使用实际请求蜂巢 OpenAPI 时的 host。以避免代理转发情况下,参与签名计算的 host 与实际请求的 host 不一致,从而导致签名不一致。
签名示例
以容器服务(ncs)的:有状态容器查询全部空间下的负载列表接口为例:
接口特定参数:
参数名 | 描述 | 示例 |
---|---|---|
Action | - | DescribeStatefulWorkloadsAllNamespaces |
Version | - | 2017-11-16 |
则查询华东某个租户全部空间下的负载列表,原始请求为:
https://open.cn-east-1.163yun.com/ncs?Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16
1. 对该请求增加公共请求参数,则该请求的所有请求参数为:
Action=DescribeStatefulWorkloadsAllNamespaces Version=2017-11-16 AccessKey=f9785e03d192401ab2464b8ca63c6e8f Timestamp=2018-01-29T04:43:02Z SignatureVersion=1.0 SignatureMethod=HMAC-SHA256 SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2 Region=cn-east-1
2. 构造标准查询字符串 CanonicalizedQueryString:
构造所有的请求参数,并对其进行编码,编码后为:
Action=DescribeStatefulWorkloadsAllNamespaces
Version=2017-11-16
AccessKey=f9785e03d192401ab2464b8ca63c6e8f
Timestamp=2018-01-29T04%3A43%3A02Z
SignatureVersion=1.0
SignatureMethod=HMAC-SHA256
SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2
Region=cn-east-1
将所有请求参数按照字典序进行排序结果为:
AccessKey=f9785e03d192401ab2464b8ca63c6e8f
Action=DescribeStatefulWorkloadsAllNamespaces
Region=cn-east-1
SignatureMethod=HMAC-SHA256
SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2
SignatureVersion=1.0
Timestamp=2018-01-29T04%3A43%3A02Z
Version=2017-11-16
将所有请求参数 Key / Value 使用 = 连接,不同的参数之间使用 & 连接,则最后生成的规范查询字符串 (CanonicalizedQueryString) 为:
AccessKey=f9785e03d192401ab2464b8ca63c6e8f&Action=DescribeStatefulWorkloadsAllNamespaces&Region=cn-east-1 &SignatureMethod=HMAC-SHA256&SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2 &SignatureVersion=1.0&Timestamp=2018-01-29T04%3A43%3A02Z&Version=2017-11-16
3. 计算请求负载的哈希值
由于该请求为 GET 方法,无 RequestBody,故使用空字符串参与计算。计算结果为:
HashedPayload=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
4. 构造 String2Sign
String2Sign 结果为:
GET\n
open.cn-east-1.163yun.com\n
/ncs\n
AccessKey=f9785e03d192401ab2464b8ca63c6e8f&Action=DescribeStatefulWorkloadsAllNamespaces&Region=cn-east-1&SignatureMethod=HMAC-SHA256&SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2&SignatureVersion=1.0&Timestamp=2018-01-29T04%3A43%3A02Z&Version=2017-11-16\n
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
5. 计算签名
假设当前 AccessKey 对应的 SecretAccessKey 为 8cfe7d5bc07949c8af7c399e19e6a346,则使用该 SK 对上述过程生成的 String2Sign 使用 HMAC-SHA256 协议计算签名并进行 Base-64 编码后,得到的签名结果为:
Yk82PRf5A8uDQ7623iwOwAll3MCHSwQpGVdq2PobYzs=
6 拼接 url
将计算得到的签名作为参数拼接到 url 中(需要遵循同样的规则进行 URLEncode )最后的请求为:
GET https://open.cn-east-1.163yun.com/ncs?AccessKey=f9785e03d192401ab2464b8ca63c6e8f&Action=DescribeStatefulWorkloadsAllNamespaces&Region=cn-east-1&SignatureMethod=HMAC-SHA256&SignatureNonce=e616388b-2509-4d29-834d-473d0f7756d2&SignatureVersion=1.0&Timestamp=2018-01-29T04:43:02Z&Version=2017-11-16&Signature=Yk82PRf5A8uDQ7623iwOwAll3MCHSwQpGVdq2PobYzs%3D
签名2
签名流程
客户端在请求时,需要按照如下步骤生成签名 Signature。
1. 构建规范请求
使用伪代码则表示如下:
CanonicalRequest = HTTPRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + Lowercase(HexEncode(Hash(RequestPayload)))
- 1.1、添加请求方法,后跟换行符
- 1.2、添加规范 URI,后跟换行符。如: /ncs
- 1.3、添加规范查询字符串,后跟换行符。若最后将公共参数以及签名信息放在 queryString 中,则该步骤中的查询参数还需要包含公共参数。
- 将所有查询参数的 key / value 进行 URL 编码
- 将所有查询参数按照 key 进行字典序排序
- 将所有查询参数的 key / value 使用 = 连接
- 将所有查询参数使用 & 连接
- 1.4、添加规范 header ,后跟换行符。规范 header 是指所有参与签名的 header,其中 host header 是必须的, x-163-date / date header 其中一个是必填的,其余标准 header 是可选的。若将公共参数以及签名信息放在 header 中,则公共参数的 header 也需要添加到规范 header 中(X-163-SignedHeaders、X-163-Signature、Authorization 除外,因为这三个公共参数的值是动态构造生成的)
- 将所有签名 header 的名称转换为小写
- 将所有签名 header 按照 header 名称进行字典序排序
- 将所有签名 header 的 value 的前导、后置空格删除(trim),将多个连续的空格转换为一个
- 将 header 的 name / value 使用 : 连接
- 将上述处理完成的所有 header 后都添加 \n (换行符)
- 1.5、添加已签名 header (SignedHeaders) , 该 header 的值是规范 header 中所有 header 的名称列表(名称应该都转换为小写),通过该 header 即可标明哪些 header 参与了签名计算。其值为:将所有的规范 header 的名称使用';'连接,后跟换行符
- 1.6、使用 SHA256 哈希函数以基于 HTTP 或 HTTPS 请求正文中的负载(body)创建哈希值,如果负载(body)为空,则使用空字符串参与计算。计算使用的哈希函数是 sha-256。
HashedPayload = Lowercase(HexEncode(Hash(requestPayload)))
- 1.7、将上述所有步骤生成的字符串拼接为一个字符串。值得注意的是:规范 header 与已签名 header 之间有一个空行
- 1.8、使用 SHA256 哈希函数对上述步骤中生成的规范请求字符串创建哈希,得到 HashedCannoicalRequest
2. 生成代签名字符串 String2Sign
使用伪代码则表示如下:
StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest
- 2.1、添加签名过程中使用到的哈希算法,后跟换行符。当前默认 HMAC-SHA256 。(请求计算签名过程中需要使用到哈希算法的地方,都需要与这里指定的哈希算法一致。)
- 2.2、添加请求时间,后跟换行符。日期使用 ISO8601 格式,UTC 时间,如:北京日期 2017年9月14日12点00分00秒 表示为 2017-09-14T04:00:00Z. (请求计算签名过程中需要使用到时间戳的地方,其值都需要与这里指定的请求时间保持一致,使用到日期的地方,其值都需要与这里指定的请求时间中日期部分保持一致。)
- 2.3、添加请求凭证范围,后跟换行符。该凭证范围的值是:日期/region/服务/163_request 。其中日期是请求时间的日期,不包含时间值。
- 2.4、添加 1 步中生成的规范请求的哈希
3、派生出签名秘钥 Signing Key
该签名秘钥是有用户访问秘钥派生出来的。使用伪代码则表示如下:
HMAC(HMAC(HMAC(HMAC("163" + SK ,"YYYYMMDD"), region), 服务), "163_request")
- 3.1、使用"163" 加上 SK 作为 key1,并用其对 日期 使用 HMAC-SHA256 算法计算出哈希值,得到 key2
- 3.2、将 key2 与 region 使用 HMAC-SHA256 算法计算出哈希值,得到 key3
- 3.3、将 key3 与 服务名称 使用 HMAC-SHA256 算法计算出哈希值,得到 key4
- 3.4、将 key4 与 服务名称 使用 HMAC-SHA256 算法计算出哈希值,得到 签名秘钥 Signing Key
4、计算签名
将第 3 步派生出的签名秘钥 Signing Key 与第 2 步生成的 String2Sign 作为加密哈希函数的输入,将得到的哈希值转换为十六进制表示形式。
5、将签名信息添加到请求中。
共有两种方式:
(1) 使用 Authorization header。
(2) 添加到 query string 中。但是需要注意的是,只能选择其中一种方式。(默认为:添加到 query string 的方式)
- 5.1、使用 Authorization header,则 Authorization 的值为:
Authorization: SignatureMethod Credential=AccessKey/credential_scope, SignedHeaders=SignedHeaders, Signature=signature
其中 SignatureMethod 为签名过程中使用的哈希算法; credential scope 为 2.c 步生成的凭证范围; SignedHeaders 为 1.e 步生成的已签名 header 名称列表; Signature 为 4 步生成的签名。若使用 Authorization header 来标明签名信息,则公共参数中的 X-163-SignatureMethod 、X-163-Credential 、X-163-SignedHeaders 都不需要。
- 5.2、使用添加 queryString 的方式,则需要在查询参数中增加 X-163-SignatureMethod 、 X-163-Credential 、 X-163-SignedHeaders 、 X-163-Signature 四个参数,且前三个参数需要添加到 1.c 步中的规范查询字符串中。
签名示例
以容器服务(ncs)的:有状态容器查询全部空间下的负载列表 接口为例。
接口特定参数:
参数名 | 描述 | 示例 |
---|---|---|
Action | - | DescribeStatefulWorkloadsAllNamespaces |
Version | - | 2017-11-16 |
则查询华东某个租户全部空间下的负载列表,原始请求为:
GET https://open.cn-east-1.163yun.com/ncs?Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16
添加公共请求参数(X-163-SignedHeaders、X-163-Signature、Authorization三个公共请求参数除外),本示例中将公共请求参数都放在header中。
则待签名的请求为:
GET https://open.cn-east-1.163yun.com/ncs?Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16
headers:
host:open.cn-east-1.163yun.com
X-163-Credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request
X-163-date:2018-02-07T03:37:27Z
X-163-SignatureMethod:HMAC-SHA256
X-163-SignatureVersion:2.0
X-163-Signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c
按照如下流程计算签名:
1. 构建规范请求
- 1.1 添加规范请求方法,后跟换行符
GET\n
- 1.2 添加规范请求 URI,后跟换行符,本请求为 /ncs
GET\n
/ncs\n
- 1.3 添加规范查询字符串,后跟换行符,本请求的查询参数有 Action(DescribeStatefulWorkloadsAllNamespaces)、Version(2017-11-16)。根据签名算法的 1.c 步骤处理后,得到规范查询字符串:Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16
GET\n
/ncs\n
Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16\n
- 1.4 添加规范 header,后跟换行符。本请求使用的日期 header 为 X-163-date 。根据签名算法的 1.d 步骤处理后,得到的规范 header 为:
host:open.cn-east-1.163yun.com\n
x-163-credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request\n
x-163-date:2018-02-07T03:37:27Z\n
x-163-signaturemethod:HMAC-SHA256\n
x-163-signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c\n
x-163-signatureversion:2.0\n
需要注意的是,这里生成的规范 header 最后已经包含了一个换行符。然后再根据 CanonicalRequest 的伪代码将规范 header append 到 1.3 步中的字符串之后,最后会多出一个换行符。
GET\n
/ncs\n
Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16\n
host:open.cn-east-1.163yun.com\n
x-163-credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request\n
x-163-date:2018-02-07T03:37:27Z\n
x-163-signaturemethod:HMAC-SHA256\n
x-163-signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c\n
x-163-signatureversion:2.0\n
\n
- 1.5 添加已签名 header (SignedHeaders),该 header 的值是规范 header 中所有 header 的名称列表(名称已转化为小写),在 1.4 中参与生成规范 header 的请求头有:x-163-credential、x-163-date、x-163-signaturemethod、x-163-signaturenonce、x-163-signatureversion、host。则请求头 SignedHeaders 的值为:x-163-credential;x-163-date;x-163-signaturemethod;x-163-signaturenonce;x-163-signatureversion;host
GET\n
/ncs\n
Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16\n
host:open.cn-east-1.163yun.com\n
x-163-credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request\n
x-163-date:2018-02-07T03:37:27Z\n
x-163-signaturemethod:HMAC-SHA256\n
x-163-signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c\n
x-163-signatureversion:2.0\n
\n
x-163-credential;x-163-date;x-163-signaturemethod;x-163-signaturenonce;x-163-signatureversion;host
- 1.6 对请求正文中的负载使用哈希函数 sha256 计算哈希值,由于本请求为 GET 方法,无 RequestBody ,则使用空字符串 "" 计算哈希,结果为: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855。则最终的 CanonicalRequest 为:
GET\n
/ncs\n
Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16\n
host:open.cn-east-1.163yun.com\n
x-163-credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request\n
x-163-date:2018-02-07T03:37:27Z\n
x-163-signaturemethod:HMAC-SHA256\n
x-163-signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c\n
x-163-signatureversion:2.0\n
\n
x-163-credential;x-163-date;x-163-signaturemethod;x-163-signaturenonce;x-163-signatureversion;host
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
2. 生成待签名字符串 String2Sign
- 2.1 添加签名过程中使用到的哈希算法,当前只支持 HMAC-SHA256,则为:
HMAC-SHA256\n
- 2.2 添加请求时间,当前请求的时间为:2018-02-07T03:37:27Z(北京时间:2018年2月7日上午11时37分27秒)
HMAC-SHA256\n
2018-02-07T03:37:27Z
- 2.3 添加请求凭证范围,当前请求的日期为20180207,请求资源所在Region为cn-east-1,请求服务的服务名称为ncs,则凭证范围为:20180207/cn-east-1/ncs/163_request
HMAC-SHA256\n
2018-02-07T03:37:27Z
20180207/cn-east-1/ncs/163_request
- 2.4 对 1 中生成的规范请求计算哈希,结果为:bb2af5725421c5d488cba7fd39e0d7cf91ad2aabe7d9aefb0ef7b03542274565
HMAC-SHA256\n
2018-02-07T03:37:27Z
20180207/cn-east-1/ncs/163_request
bb2af5725421c5d488cba7fd39e0d7cf91ad2aabe7d9aefb0ef7b03542274565
3. 派生 signing key
使用访问密钥对的 accessKey 以及 日期、服务名称、region 派生出 signing key
HMAC(HMAC(HMAC(HMAC("163" + SK ,"YYYYMMDD"), region), 服务), "163_request")
需要注意的是,HMAC 每一步计算出的结果都为二进制数组,最终计算结果 signing key 也是一个二进制数组。
4. 计算签名
使用 signing key 与 string2sign 计算签名,结果为:d5ac614c89ae3f554006fc9dbd277c60721a7c277ed4c247fc80edbcd2dc639c
5. 将签名信息添加到请求中
这里选用的是将签名作为一个独立的参数放到请求头中,该请求头信息为:
X-163-Signature:d5ac614c89ae3f554006fc9dbd277c60721a7c277ed4c247fc80edbcd2dc639c 则最终发送到蜂巢平台的请求为:(在待签名请求的基础上增加了两个请求头:X-163-Signature、X-163-SignedHeaders)
GET https://open.cn-east-1.163yun.com/ncs?Action=DescribeStatefulWorkloadsAllNamespaces&Version=2017-11-16
headers:
X-163-Credential:f9785e03d192401ab2464b8ca63c6e8f/20180207/cn-east-1/ncs/163_request
host:open.cn-east-1.163yun.com
X-163-date:2018-02-07T03:37:27Z
X-163-SignatureMethod:HMAC-SHA256
X-163-SignatureVersion:2.0
X-163-Signaturenonce:b5ab42cf-ec73-4167-9114-c7b4182b848c
X-163-SignedHeaders:x-163-credential;x-163-date;x-163-signaturemethod;x-163-signaturenonce;x-163-signatureversion;host
X-163-Signature:d5ac614c89ae3f554006fc9dbd277c60721a7c277ed4c247fc80edbcd2dc639c