函数计算产品提供的API采用ROA签名风格,本文介绍V3版本的签名机制,更多信息,请参见V3版本请求体&签名机制。
签名机制
采用AK/SK方式进行签名与认证。对于每一次HTTP或HTTPS协议请求,阿里云API网关将依据请求参数信息重新计算签名,通过对比该签名与请求中提供的签名是否一致,从而验证请求者的身份,以确保传输数据的完整性与安全性。
请求及返回结果都使用UTF-8字符集进行编码。
步骤一:构造规范化请求
构造规范化请求(CanonicalRequest)的伪代码如下:
CanonicalRequest =
HTTPRequestMethod + '\n' + // http请求方法,全大写
CanonicalURI + '\n' + // 规范化URI
CanonicalQueryString + '\n' + // 规范化查询字符串
CanonicalHeaders + '\n' + // 规范化消息头
SignedHeaders + '\n' + // 已签名消息头
HashedRequestPayload // 请求body的hash值
HTTPRequestMethod(请求方法)
即大写的HTTP方法名,如GET、POST。
CanonicalURI(规范化URI)
URL的资源路径部分经过编码之后的结果。资源路径部分指URL中host与查询字符串之间的部分,包含host之后的
/
但不包含查询字符串前的?
。用户发起请求时的URI应使用规范化URI,编码方式使用UTF-8字符集按照RFC3986的规则对URI中的每一部分(即被/
分割开的字符串)进行编码:字符A~Z、a~z、0~9以及字符
-
、_
、.
、~
不编码。其他字符编码成
%
加字符对应ASCII码的16进制。示例:半角双引号("
)对应%22
。需要注意的是,部分特殊字符需要特殊处理,具体如下:编码前
编码后
空格( )
%20
星号(
*
)%2A
%7E
波浪号(
~
)如果您使用的是Java标准库中的
java.net.URLEncoder
,可以先用标准库中encode
编码,随后将编码后的字符中加号(+
)替换为%20
、星号(*
)替换为%2A
、%7E
替换为波浪号(~
),即可得到上述规则描述的编码字符串。
重要RPC风格API使用正斜杠(
/
)作为CanonicalURI,ROA风格API该参数为OpenAPI元数据中
path
的值,例如/api/v1/clusters
。CanonicalQueryString(规范化查询字符串)
在OpenAPI元数据中,如果API的请求参数信息包含了
"in":"query"
时,需要将这些请求参数按照如下构造方法拼接起来:将请求参数按照参数名称的字符顺序升序排列。
使用UTF-8字符集按照RFC3986的规则对每个参数的参数名称和参数值分别进行URI编码,具体规则与上一节中的CanonicalURI编码规则相同。
使用等号(
=
)连接编码后的请求参数名称和参数值,对于没有值的参数使用空字符串。多个请求参数之间使用与号(
&
)连接。
重要当请求参数类型是array、object时,需要将参数平铺为一个映射结构(map)。例如
{"ImageId":"win2019_1809_x64_dtc_zh-cn_40G_alibase_20230811.vhd","RegionId":"cn-shanghai","Tag":[{"tag1":"value1","tag2":"value2"}]}
平铺后为{"ImageId":"win2019_1809_x64_dtc_zh-cn_40G_alibase_20230811.vhd","RegionId":"cn-shanghai","Tag.1.tag1":"value1","Tag.1.tag2":"value2"}
。当请求的查询字符串为空时,使用空字符串作为规范化查询字符串。
示例值:
ImageId=win2019_1809_x64_dtc_zh-cn_40G_alibase_20230811.vhd&RegionId=cn-shanghai
HashedRequestPayload
使用哈希函数对RequestPayload进行转换得到HashedRequestPayload,并将RequestHeader中
x-acs-content-sha256
的值修改为HashedRequestPayload的值。伪代码如下:HashedRequestPayload = HexEncode(Hash(RequestPayload))
RequestPayload的值有以下两种情况:
在OpenAPI元数据中,如果API的请求参数信息包含了
"in": "body"
或"in": "formData"
时,需通过请求body传递参数,RequestPayload的值为请求body对应的JSON字符串。重要当请求参数信息包含
"in": "formData"
时,需要将这类参数按照固定格式拼接为一个字符串,拼接格式为:key1=value1&key2=value2&key3=value3
。若请求参数类型是array、object时,需要将参数平铺为一个映射结构(map)。例如{"key":["value1","value2"]}
平铺后为{"key.1":"value1","key.2":"value2"}
。同时需要在RequestHeader中添加content-type=application/x-www-form-urlencoded
。当请求参数信息包含
"in": "body"
时,需要在RequestHeader中添加content-type,content-type的值与请求内容类型有关。例如:请求内容类型为JSON数据时,content-type的值为
application/json
。请求内容类型为二进制文件流时,content-type的值为
application/octet-stream
。
若没有请求body,RequestPayload的值固定为一个空字符串。
Hash表示消息摘要函数,目前仅支持SHA256算法。
HexEncode表示以小写的十六进制的形式返回摘要的编码函数(即Base16编码)。
当请求body为空时的示例值:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
CanonicalHeaders(规范化请求头)
将RequestHeader中的参数按照如下构造方法拼接起来:
过滤出RequestHeader中包含以
x-acs-
为前缀、host
、content-type
的参数。将参数的名称转换为小写,并按照字符顺序升序排列。
将参数的值去除首尾空格。
将参数名称和参数值以英文冒号(
:
)连接,并在尾部添加换行符(\n
),组成一个规范化消息头(CanonicalHeaderEntry)。将多个规范化消息头(CanonicalHeaderEntry)拼接成一个字符串。
说明除Authorization外的所有RequestHeader,只要符合要求都必须被加入签名。
伪代码如下:
CanonicalHeaderEntry = Lowercase(HeaderName) + ':' + Trim(HeaderValue) + '\n' CanonicalHeaders = CanonicalHeaderEntry0 + CanonicalHeaderEntry1 + ... + CanonicalHeaderEntryN
示例值:
host:ecs.cn-shanghai.aliyuncs.com x-acs-action:RunInstances x-acs-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-acs-date:2023-10-26T10:22:32Z x-acs-signature-nonce:3156853299f313e23d1673dc12e1703d x-acs-version:2014-05-26
SignedHeaders(已签名消息头列表)
用于说明此次请求中参与签名的公共请求头信息,与CanonicalHeaders中的参数名称一一对应。其构造方法如下:
将CanonicalHeaders中包含的请求头的名称转为小写。
按首字母升序排列并以英文分号(
;
)分隔。
伪代码如下:
SignedHeaders = Lowercase(HeaderName0) + ';' + Lowercase(HeaderName1) + ... + Lowercase(HeaderNameN)
示例值:
host;x-acs-action;x-acs-content-sha256;x-acs-date;x-acs-signature-nonce;x-acs-version
步骤二:构造待签名字符串
按照以下伪代码构造待签名字符串(stringToSign):
StringToSign =
SignatureAlgorithm + '\n' +
HashedCanonicalRequest
SignatureAlgorithm
签名协议目前仅支持ACS3-HMAC-SHA256算法。
HashedCanonicalRequest
规范化请求摘要串,计算方法伪代码如下:
HashedCanonicalRequest = HexEncode(Hash(CanonicalRequest))
Hash表示消息摘要函数,目前仅支持SHA256算法。
HexEncode表示以小写的十六进制的形式返回摘要的编码函数(即Base16编码)。
示例值:
ACS3-HMAC-SHA256
7ea06492da5221eba5297e897ce16e55f964061054b7695beedaac1145b1e259
步骤三:计算签名
按照以下伪代码计算签名值(Signature)。
Signature = HexEncode(SignatureMethod(Secret, StringToSign))
StringToSign:步骤二中构造的待签名字符串,UTF-8编码。
SignatureMethod:使用HMAC-SHA256作为签名算法。
Secret:AccessKey Secret。
HexEncode:以小写的十六进制的形式返回摘要的编码函数(即Base16编码)。
示例值:
06563a9e1b43f5dfe96b81484da74bceab24a1d853912eee15083a6f0f3283c0
步骤四:将签名添加到请求中
计算完签名后,构造Authorization请求头,格式为:Authorization:<SignatureAlgorithm> Credential=<AccessKeyId>,SignedHeaders=<SignedHeaders>,Signature=<Signature>
。
示例值:
ACS3-HMAC-SHA256 Credential=YourAccessKeyId,SignedHeaders=host;x-acs-action;x-acs-content-sha256;x-acs-date;x-acs-signature-nonce;x-acs-version,Signature=06563a9e1b43f5dfe96b81484da74bceab24a1d853912eee15083a6f0f3283c0