全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网 钉钉智能硬件
日志服务

请求签名

更新时间:2017-06-07 13:26:11

为保证用户日志数据的安全,Log Service API 的所有 HTTP 请求都必须经过安全验证。目前,该安全验证基于阿里云的 访问秘钥,使用对称加密算法完成的。

其工作流程如下:

  1. 请求端根据 API 请求内容(包括 HTTP Header 和 Body)生成签名字符串。
  2. 请求端使用阿里云的访问秘钥对(AccessKeyID 和 AccessKeySecret)对第一步生成的签名字符串进行签名,形成该 API 请求的数字签名。
  3. 请求端把 API 请求内容和数字签名一同发送给服务端。
  4. 服务端在接到请求后会重复如上的第一、二步工作(注意:服务端会在后台取得该请求使用的用户访问秘钥对)并在服务端计算出该请求期望的数字签名。
  5. 服务端用期望的数字签名和请求端发送过来的数字签名做比对,如果完全一致则认为该请求通过安全验证。否则直接拒绝该请求。

上面的整个流程也可以使用下图直观描述:

上面的安全验证流程可以达到如下目的:

  • 确认哪位用户在做 API 请求。因为在发送请求前需要用户指定生成数字签名的秘钥对,在服务端即可通过该秘钥对确定用户身份,进而可做访问权限管理。
  • 确认用户请求在网络传输过程中有无被篡改。因为服务端会对接收到的请求内容重新计算数字签名,一旦请求内容在网络上被篡改,则无法通过数字签名比对。

签名 API 请求

为了通过 API 请求的安全验证,用户需要在客户端对其 API 请求进行签名(即生成正确的数字签名),并且使用 HTTP 头 Authorization 在网络上传输该请求的数字签名。Authorization 头的具体格式如下:

  1. Authorization:LOG <AccessKeyId>:<Signature>

如上格式所示,Authorization 头的值包含用户访问秘钥对中的 AccessKeyId,且与之对应的 AccessKeySecret 将用于 Signature 值的构造。下面将详细解释如何构造该 Signature 值。

第一步:准备合适的阿里云访问秘钥

如上所述,给 API 请求生成签名,需使用一对访问秘钥(AccessKeyId/AccessKeySecret)。您可以使用已经存在的访问秘钥对,也可以创建新的访问秘钥对,但需要保证使用的秘钥对处在“启用”状态。

第二步:生成请求的签名字符串

Log Service API 的签名字符串由 HTTP 请求中的 Method,Header 和 Body 信息一同生成,具体方式如下:

  1. SignString = VERB + "\n"
  2. + CONTENT-MD5 + "\n"
  3. + CONTENT-TYPE + "\n"
  4. + DATE + "\n"
  5. + CanonicalizedLOGHeaders + "\n"
  6. + CanonicalizedResource

上面公式中的 \n 表示换行转义字符,+(加号)表示字符串连接操作,其他各个部分定义如下:

名称 定义 示例
VERB HTTP 请求的方法名称 PUT、GET、POST 等
CONTENT-MD5 HTTP 请求中 Body 部分的 MD5 值(必须为大写字母串) 875264590688CA6171F6228AF5BBB3D2
CONTENT-TYPE HTTP 请求中 Body 部分的类型 application/x-protobuf
DATE HTTP 请求中的标准时间戳头(遵循 RFC 1123 格式,使用 GMT 标准时间) Mon, 3 Jan 2010 08:33:47 GMT
CanonicalizedLOGHeaders 由 HTTP 请求中以 x-logx-acs 为前缀的自定义头构造的字符串(具体构造方法见下面详述) x-log-apiversion:0.6.0\nx-log-bodyrawsize:50\nx-log-signaturemethod:hmac-sha1
CanonicalizedResource 由 HTTP 请求资源构造的字符串(具体构造方法见下面详述) /logstores/app_log

对于部分无 Body 的 HTTP 请求,其 CONTENT-MD5 和 CONTENT-TYPE 两个域为空字符串,这时整个签名字符串的生成方式如下:

  1. SignString = VERB + "\n"
  2. + "\n"
  3. + "\n"
  4. + DATE + "\n"
  5. + CanonicalizedLOGHeaders + "\n"
  6. + CanonicalizedResource

正如 公共请求头 中描述,Log Service API 中引入了一个自定义请求头 x-log-date。如果您在请求中指定了该请求头,则其值会替代 HTTP 标准请求头 Date 加入签名计算。

CanonicalizedLOGHeaders 的构造方式如下:

  1. 将所有以 x-logx-acs 为前缀的 HTTP 请求头的名字转换成小写字母;
  2. 将上一步得到的所有 LOG 自定义请求头按照字典序进行升序排序;
  3. 删除请求头和内容之间分隔符两端出现的任何空格;
  4. 将所有的头和内容用 \n 分隔符组合成最后的 CanonicalizedLOGHeader。

CanonicalizedResource 的构造方式如下:

  1. 将 CanonicalizedResource 设置为空字符串(””);
  2. 放入要访问的 LOG 资源,如 /logstores/logstorename(无 logstorename 则不填);
  3. 如请求包含查询字符串(QUERY_STRING),则在 CanonicalizedResource 字符串尾部添加 和查询字符串。

其中,QUERY_STRING 是 URL 中请求参数按字典序排序后的字符串,其中参数名和值之间用 = 相隔组成字符串,并对参数名-值对按照字典序升序排序,然后以 & 符号连接构成字符串。其公式化描述如下:

  1. QUERY_STRING = "KEY1=VALUE1" + "&" + "KEY2=VALUE2"
第三步:生成请求的数字签名

目前,Log Service API 只支持一种数字签名算法,即默认签名算法 hmac-sha1。其整个签名公式如下:

  1. Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret))

签名的方法用 RFC 2104 中定义的 HMAC-SHA1 方法。如上公式用的 AccessKeySecret 必须和最终的 Authorization 头中使用的 AccessKeyId 相对应。否则,请求将无法通过服务端验证。

在计算出数字签名后,使用该值按本节最前面描述的 Authorization 头格式构建完整的 Log Service API 请求安全验证头,并填入 HTTP 请求中即可发送。

请求签名过程示例

为更好地理解整个请求签名的流程,我们用两个示例来演示整个过程。首先,假设您用做 Log Service API 签名的访问秘钥对如下:

  1. AccessKeyId = "bq2sjzesjmo86kq35behupbq"
  2. AccessKeySecret = "4fdO2fTDDnZPU/L7CHNdemB2Nsk="

示例一:

您需要发送如下 GET 请求列出 ali-test-project 项目下的所有 LogStores,其 HTTP 请求如下:

  1. GET /logstores HTTP 1.1
  2. Mon, 09 Nov 2015 06:11:16 GMT
  3. Host: ali-test-project.cn-hangzhou-devcommon-intranet.sls.aliyuncs.com
  4. x-log-apiversion: 0.6.0
  5. x-log-signaturemethod: hmac-sha1

如上 Log Service API 请求生成的签名字符串为:

  1. GET\n\n\nMon, 09 Nov 2015 06:11:16 GMT\nx-log-apiversion:0.6.0\nx-log-signaturemethod:hmac-sha1\n/logstores?logstoreName=&offset=0&size=1000

由于是 GET 请求,该请求无任何 HTTP Body,所以生成的签名字符串中 CONTENT-TYPE 与 CONTENT-MD5 域为空字符串。如果以前面指定的 AccessKeySecret 做签名运算后得到的签名为:

  1. jEYOTCJs2e88o+y5F4/S5IsnBJQ=

最后发送经数字签名的 HTTP 请求内容如下:

  1. GET /logstores HTTP 1.1
  2. Mon, 09 Nov 2015 06:11:16 GMT
  3. Host: ali-test-project.cn-hangzhou-devcommon-intranet.sls.aliyuncs.com
  4. x-log-apiversion: 0.6.0
  5. x-log-signaturemethod: hmac-sha1
  6. Authorization: LOG bq2sjzesjmo86kq35behupbq:jEYOTCJs2e88o+y5F4/S5IsnBJQ=

示例二:

您需要给同上例 ali-test-project 项目中名为 test-logstore 的 Logstore 写入下面的日志:

  1. topic=""
  2. time=1447048976
  3. source="10.230.201.117"
  4. "TestKey": "TestContent"

为此,按照 Log Service API 定义需要构建如下 HTTP 请求:

  1. POST /logstores/test-logstore HTTP/1.1
  2. Date: Mon, 09 Nov 2015 06:03:03 GMT
  3. Host: test-project.cn-hangzhou-devcommon-intranet.sls.aliyuncs.com
  4. x-log-apiversion: 0.6.0
  5. x-log-signaturemethod: hmac-sha1
  6. Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
  7. Content-Length: 52
  8. x-log-apiversion:0.6.0
  9. x-log-bodyrawsize:50
  10. x-log-compresstype:lz4
  11. x-log-signaturemethod:hmac-sha1
  12. <日志内容序列化成 ProtoBuffer 格式的字节流>

在这个 HTTP 请求中,写入的日志内容首先被序列化成 ProtoBuffer 格式(请参考 ProtoBuffer格式 了解该格式的更多细节)后作为请求 Body。所以该请求的 Content-Type 头的值指定为 application/x-protobuf。类似,Content-MD5 头的值是请求 body 对应的 MD5 值。按照上面的签名字符串构造方式,这个请求对应的签名字符串为:

  1. POST\n1DD45FA4A70A9300CC9FE7305AF2C494\napplication/x-protobuf\nMon, 09 Nov 2015 06:03:03 GMT\nx-log-apiversion:0.6.0\nx-log-bodyrawsize:50\nx-log-compresstype:lz4\nx-log-signaturemethod:hmac-sha1\n/logstores/test-logstore

同样,以前面示例中的 AccessKeySecret 做签名运算,得到的最终签名为:

  1. XWLGYHGg2F2hcfxWxMLiNkGki6g=

最后发送经数字签名的 HTTP 请求内容如下:

  1. POST /logstores/test-logstore HTTP/1.1
  2. Date: Mon, 09 Nov 2015 06:03:03 GMT
  3. Host: test-project.cn-hangzhou-devcommon-intranet.sls.aliyuncs.com
  4. x-log-apiversion: 0.6.0
  5. x-log-signaturemethod: hmac-sha1
  6. Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
  7. Content-Length: 52
  8. x-log-apiversion:0.6.0
  9. x-log-bodyrawsize:50
  10. x-log-compresstype:lz4
  11. x-log-signaturemethod:hmac-sha1
  12. Authorization: LOG bq2sjzesjmo86kq35behupbq:XWLGYHGg2F2hcfxWxMLiNkGki6g=
  13. <日志内容序列化成 ProtoBuffer 格式的字节流>
本文导读目录