阿里云日志服务请求签名

为保证用户日志数据的安全,日志服务 API 的所有 HTTP 请求都必须经过安全验证。

验证流程

目前,该安全验证基于阿里云的访问密钥,使用对称加密算法完成。

其验证流程如下:

  1. 请求端根据 API 请求内容(包括 HTTP Header 和 Body)生成签名字符串。
  2. 请求端使用阿里云的访问密钥对(AccessKeyID 和 AccessKeySecret),对第一步生成的签名字符串进行签名,形成该 API 请求的数字签名。
  3. 请求端把 API 请求内容和数字签名一同发送给服务端。
  4. 服务端在接到请求后会重复如上的步骤1和步骤2的工作,并在服务端计算出该请求期望的数字签名。


    说明 服务端会在后台取得该请求使用的用户访问密钥对。

  5. 服务端用期望的数字签名和请求端发送过来的数字签名做比对,如果完全一致则认为该请求通过安全验证。否则直接拒绝该请求。

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

图 1. 安全验证流程
全验证流程全验证流程

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

  • 确认哪位用户在做 API 请求。

    因为在发送请求前需要用户指定生成数字签名的密钥对,在服务端即可通过该密钥对确定用户身份,进而可做访问权限管理。

  • 确认用户请求在网络传输过程中有无被篡改。

    因为服务端会对接收到的请求内容重新计算数字签名,一旦请求内容在网络上被篡改,则无法通过数字签名比对。

签名 API 请求

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

Authorization:LOG <AccessKeyId>:<Signature>

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

  1. 准备阿里云访问密钥。

    为 API 请求生成签名,需使用一对访问密钥(AccessKeyId/AccessKeySecret)。您可以使用已经存在的访问密钥对,也可以创建新的访问密钥对,但需要保证使用的密钥对为启用状态。

  2. 生成请求的签名字符串。

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

    SignString = VERB + "\n"
                 + CONTENT-MD5 + "\n"
                 + CONTENT-TYPE + "\n"
                 + DATE + "\n"
                 + CanonicalizedLOGHeaders + "\n"
                 + CanonicalizedResource

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

    表 1. 签名字符串定义
    名称 定义 示例
    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 两个域为空字符串,这时整个签名字符串的生成方式如下:

    SignString = VERB + "\n"
                 + "\n"
                 + "\n"
                 + DATE + "\n"
                 + CanonicalizedLOGHeaders + "\n"
                 + CanonicalizedResource

    如公共请求头中的描述,日志服务 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 中请求参数按字典顺序排序后的字符串,其中参数名和值之间用 = 相隔组成字符串,并对参数名-值对按照字典顺序升序排序,然后以 & 符号连接构成字符串。其公式化描述如下:

      QUERY_STRING = "KEY1=VALUE1" + "&" + "KEY2=VALUE2"
  3. 生成请求的数字签名。

    目前,日志服务 API 只支持一种数字签名算法,即默认签名算法 hmac-sha1。其完整签名公式如下:

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

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

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

请求签名过程示例

为了帮助您更好地理解整个请求签名的流程,我们用两个示例来演示整个过程。首先,假设您用做日志服务 API 签名的访问密钥对如下:

AccessKeyId = "bq2sjzesjmo86kq*********"
AccessKeySecret = "4fdO2fTDDnZPU/L7CHNd********"
  • 示例一

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

    GET /logstores HTTP 1.1
    Mon, 09 Nov 2015 06:11:16 GMT
    Host: ali-test-project.regionid.example.com
    x-log-apiversion: 0.6.0
    x-log-signaturemethod: hmac-sha1

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

    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 做签名运算后得到的签名为:

    jEYOTCJs2e88o+y5F4/S5IsnBJQ=

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

    GET /logstores HTTP 1.1
    Mon, 09 Nov 2015 06:11:16 GMT
    Host: ali-test-project.regionid.example.com
    x-log-apiversion: 0.6.0
    x-log-signaturemethod: hmac-sha1
    Authorization: LOG bq2sjzesjmo86kq35behupbq:jEYOTCJs2e88o+y5F4/S5IsnBJQ=
  • 示例二

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

    topic=""
    time=1447048976
    source="10.10.10.1"
    "TestKey": "TestContent"

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

    POST /logstores/test-logstore HTTP/1.1
    Date: Mon, 09 Nov 2015 06:03:03 GMT
    Host: test-project.regionid.example.com
    x-log-apiversion: 0.6.0
    x-log-signaturemethod: hmac-sha1
    Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
    Content-Length: 52
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:50
    x-log-compresstype:lz4
    x-log-signaturemethod:hmac-sha1
    <日志内容序列化成 ProtoBuffer 格式的字节流>

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

    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 做签名运算,得到的最终签名为:

    XWLGYHGg2F2hcfxWxMLiNkGki6g=

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

    POST /logstores/test-logstore HTTP/1.1
    Date: Mon, 09 Nov 2015 06:03:03 GMT
    Host: test-project.regionid.example.com
    x-log-apiversion: 0.6.0
    x-log-signaturemethod: hmac-sha1
    Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
    Content-Length: 52
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:50
    x-log-compresstype:lz4
    x-log-signaturemethod:hmac-sha1
    Authorization: LOG bq2sjzesjmo86kq35behupbq:XWLGYHGg2F2hcfxWxMLiNkGki6g=
    <日志内容序列化成ProtoBuffer格式的字节流>

原创文章,作者:网友投稿,如若转载,请注明出处:https://www.cloudads.cn/archives/33836.html

发表评论

登录后才能评论