文档首页 > > API签名指南> AK/SK签名认证算法详解

AK/SK签名认证算法详解

分享
更新时间: 2019/06/06 09:45

客户端涉及的AK/SK签名以及请求发送的流程概述如下:

  1. 构造规范请求

    将待发送的请求内容按照与API网关后台约定的规则组装,确保客户端签名、API网关后台认证时使用的请求内容一致。

  2. 使用规范请求和其他信息创建待签字符串
  3. 使用AK/SK和待签字符串计算签名
  4. 将生成的签名信息作为请求消息头添加到HTTP请求中,或者作为查询字符串参数添加到HTTP请求中。

以下做详细介绍。

步骤1:构造规范请求

使用AK/SK方式进行签名与认证,首先需要规范请求内容,然后再进行签名。客户端与云服务API网关使用相同的请求规范,可以确保同一个HTTP请求的前后端得到相同的签名结果,从而完成身份校验。

HTTP请求规范伪代码如下:
CanonicalRequest =
      HTTPRequestMethod + '\n' +
      CanonicalURI + '\n' +
      CanonicalQueryString + '\n' +
      CanonicalHeaders + '\n' +
      SignedHeaders + '\n' +
      HexEncode(Hash(RequestPayload))

我们以虚拟私有云服务的一个查询VPC列表接口为例,说明规范请求的构造步骤。

假设原始请求:

GET https://service.region.example.com/v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs?limit=2&marker=13551d6b-755d-4757-b956-536f674975c0 HTTP/1.1
Host: service.region.example.com
X-Sdk-Date: 20190329T074551Z
  1. 构造HTTP请求方法HTTPRequestMethod),以换行符结束。

    HTTP请求方法,如GET、PUT、POST等。请求方法示例:

    GET

  2. 添加规范URI参数CanonicalURI),以换行符结束。

    释义

    规范URI,即请求资源路径,是URI的绝对路径部分的URI编码。

    格式

    根据RFC 3986标准化URI路径,移除冗余和相对路径部分,路径中每个部分必须为URI编码。如果URI路径不以“/”结尾,则在尾部添加“/”。

    举例

    URI具体见云服务的API参考手册,每个API章节都提供对应的资源路径。如虚拟私有云服务的查询VPC列表:/v1/{project_id}/vpcs,此时规范的URI编码为:

    GET
    /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/
    说明:

    计算签名时,URI必须以“/”结尾。发送请求时,可以不以“/”结尾。

  3. 添加规范查询字符串(CanonicalQueryString,以换行符结束。

    释义

    查询字符串,即查询参数。如果没有查询参数,则为空字符串,即规范后的请求为空行

    格式:

    规范查询字符串需要满足以下要求:

    • 根据以下规则对每个参数名和值进行URI编码:
      • 请勿对RFC 3986定义的任何非预留字符进行URI编码,这些字符包括:A-Z、a-z、0-9、-、_、.和~。
      • 使用%XY对所有非预留字符进行百分比编码,其中X和Y为十六进制字符(0-9和A-F)。例如,空格字符必须编码为%20,扩展UTF-8字符必须采用“%XY%ZA%BC”格式。
    • 对于每个参数,追加“URI编码的参数名称=URI编码的参数值”。如果没有参数值,则以空字符串代替,但不能省略“=”。
      例如以下含有两个参数,其中第二个参数parm2的值为空。
      parm1=value1&parm2=
    • 按照字符代码以升序顺序对参数名进行排序。例如,以大写字母F开头的参数名排在以小写字母b开头的参数名之前。
    • 以排序后的第一个参数名开始,构造规范查询字符串。

    举例

    查询VPC列表有两个可选参数:limit(每页返回的个数)、marker(分页查询的起始VPC资源ID)
    GET
    /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/
    limit=2&marker=13551d6b-755d-4757-b956-536f674975c0

  4. 添加规范消息头CanonicalHeaders),以换行符结束。

    释义

    规范消息头,即请求消息头列表。包括签名请求中的所有HTTP消息头列表。消息头必须包含X-Sdk-Date,用于校验签名时间,格式为ISO8601标准的UTC时间格式:YYYYMMDDTHHMMSSZ。

    格式

    CanonicalHeaders由多个请求消息头共同组成,CanonicalHeadersEntry0 + CanonicalHeadersEntry1 + ...,其中每个请求消息头(CanonicalHeadersEntry )的格式为Lowercase(HeaderName) + ':' + Trimall(HeaderValue) + '\n'

    说明:
    • Lowercase表示将所有字符转换为小写字母的函数。
    • Trimall表示删除值前后的多余空格的函数。
    • 最后一个请求消息头也会携带一个换行符。叠加规范中CanonicalHeaders自身携带的换行符,因此会出现一个空行。

    举例

    查询VPC列表的消息头,需要包含签名时间(X-Sdk-Date),云服务Endpoint(Host)、内容类型(Content-Type)。
    GET
    /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/
    limit=2&marker=13551d6b-755d-4757-b956-536f674975c0
    content-type:application/json
    host:service.region.example.com
    x-sdk-date:20190329T074551Z

    规范消息头需要满足以下要求:

    • 将消息头名称转换为小写形式,并删除前导空格和尾随空格。
    • 按照字符代码对消息头名称进行升序排序。

    例如原始消息头为:

    Host: service.region.example.com\n
    Content-Type: application/json;charset=utf8\n
    My-header1:    a   b   c  \n
    X-Sdk-Date:20190318T094751Z\n
    My-Header2:    "x   y   \n

    对消息头名称转小写,按消息头名称字符代码对消息头排序,将消息头的值去掉前导空格与尾随空格。最终得到规范消息头:

    content-type:application/json;charset=utf8\n
    host:service.region.example.com\n
    my-header1:a   b   c\n
    my-header2:"x   y\n
    x-sdk-date:20190318T094751Z\n
    

  5. 添加用于签名的消息头声明SignedHeaders),以换行符结束。

    释义

    用于签名的请求消息头列表。通过添加此消息头,向API网关告知请求中哪些消息头是签名过程的一部分,以及在验证请求时API网关可以忽略哪些消息头。X-Sdk-date必须作为已签名的消息头。

    格式

    SignedHeaders = Lowercase(HeaderName0) + ';' + Lowercase(HeaderName1) + ";" + ...

    已签名的消息头需要满足以下要求:将已签名的消息头名称转换为小写形式,按照字符代码对消息头进行排序,并使用“;”来分隔多个消息头。

    Lowercase表示将所有字符转换为小写字母。

    举例

    以下表示有三个消息头参与签名:Content-Type、Host、X-Sdk-Date
    GET
    /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/
    limit=2&marker=13551d6b-755d-4757-b956-536f674975c0
    content-type:application/json
    host:service.region.example.com
    x-sdk-date:20190329T074551Z
    
    content-type;host;x-sdk-date

  6. 使用SHA 256哈希函数以基于HTTP或HTTPS请求正文中的body体(RequestPayload),创建哈希值。

    释义

    请求消息体。消息体需要做两层转换:HexEncode(Hash(RequestPayload)),其中Hash表示生成消息摘要的函数,当前支持SHA-256算法。HexEncode表示以小写字母形式返回摘要的Base-16编码的函数。例如,HexEncode("m") 返回值为“6d”而不是“6D”。输入的每一个字节都表示为两个十六进制字符。

    说明:

    计算RequestPayload的哈希值时,对于“RequestPayload==null”的场景,直接使用空字符串""来计算。

    举例

    本示例为GET方法,body体为空。经过哈希处理的body(空字符串)如下:

    GET
    /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/
    limit=2&marker=13551d6b-755d-4757-b956-536f674975c0
    content-type:application/json
    host:service.region.example.com
    x-sdk-date:20190329T074551Z
    
    content-type;host;x-sdk-date
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

    至此,规范请求构造完成。

  7. 对构造好的规范请求进行哈希处理,算法与对RequestPayload哈希处理的算法相同。经过哈希处理的规范请求必须以小写十六进制字符串形式表示。

    算法伪代码:Lowercase(HexEncode(Hash.SHA256(CanonicalRequest)))

    经过哈希处理的规范请求示例:

    9f5ad2be0a6921a5ea888f13f3e1a750da9c45e6978812ffafc140bdecba1174

步骤2:创建待签字符串

对HTTP请求进行规范并取得请求的哈希值后,将其与签名算法、签名时间一起组成待签名字符串。
StringToSign =
    Algorithm + \n +
    RequestDateTime + \n +
    HashedCanonicalRequest

伪代码中参数说明如下。

  • Algorithm

    签名算法。对于SHA 256,算法为SDK-HMAC-SHA256

  • RequestDateTime

    请求时间戳。与请求消息头X-Sdk-Date的值相同,格式为YYYYMMDDTHHMMSSZ。

  • HashedCanonicalRequest

    经过哈希处理的规范请求。

上述例子得到的待签字符串为:
SDK-HMAC-SHA256
20190329T074551Z
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

步骤3:计算签名

将SK(Access Secret Key)和创建的待签字符串作为加密哈希函数的输入,计算签名,将二进制值转换为十六进制表示形式。

伪代码如下:

signature = HexEncode(HMAC(Access Secret Key, string to sign))

其中HMAC指密钥相关的哈希运算,HexEncode指转十六进制。伪代码中参数说明如表1所示。

表1 参数说明

参数名称

参数解释

Access Secret Key

签名密钥

string to sign

创建的待签字符串

假设Access Secret Key为MFyfvK41ba2giqM7Uio6PznpdUKGpownRZlmVmHc,则计算得到的signature为:

9f5ad2be0a6921a5ea888f13f3e1a750da9c45e6978812ffafc140bdecba1174

步骤4:添加签名信息到请求头

在计算签名后,将它添加到Authorization的HTTP消息头。Authorization消息头未包含在已签名消息头中,主要用于身份验证。

伪代码如下:

Authorization header创建伪码:
Authorization: algorithm Access=Access key, SignedHeaders=SignedHeaders, Signature=signature

需要注意的是算法与Access之前有空格但没有逗号,但是SignedHeaders与Signature之前需要使用逗号隔开。

得到的签名消息头为:

SDK-HMAC-SHA256 Access=QTWAOYTTINDUT2QVKYUC, SignedHeaders=content-type;host;x-sdk-date, Signature=d66f6a6c536e984129e13a4060f465225909fd126d212cb25e9e292346aae036

得到签名消息头后,将其增加到原始HTTP请求内容中,请求将被发送给云服务API网关,由API网关完成身份认证。身份认证通过后,该请求才会发送给具体的云服务进行业务处理。

包含签名信息的完整请求如下:

GET /v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs?limit=2& marker=13551d6b-755d-4757-b956-536f674975c0 HTTP/1.1
Host: service.region.example.com
Content-Type: application/json
x-sdk-date: 20190329T074551Z
Authorization: SDK-HMAC-SHA256 Access=QTWAOYTTINDUT2QVKYUC, SignedHeaders=content-type;host;x-sdk-date, Signature=d66f6a6c536e984129e13a4060f465225909fd126d212cb25e9e292346aae036

Curl方式样例如下:

curl -X GET "https://service.region.example.com/v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs?limit=2&marker=13551d6b-755d-4757-b956-536f674975c0" -H "Content-Type: application/json" -H "X-Sdk-Date: 20190329T074551Z" -H "host: service.region.example.com" -H "Authorization: SDK-HMAC-SHA256 Access=QTWAOYTTINDUT2QVKYUC, SignedHeaders=content-type;host;x-sdk-date, Signature=d66f6a6c536e984129e13a4060f465225909fd126d212cb25e9e292346aae036" -d $''

分享:

    相关文档

    相关产品

文档是否有解决您的问题?

提交成功!

非常感谢您的反馈,我们会继续努力做到更好!

反馈提交失败,请稍后再试!

*必选

请至少选择或填写一项反馈信息

字符长度不能超过200

提交反馈 取消

如您有其它疑问,您也可以通过华为云社区问答频道来与我们联系探讨

跳转到云社区