You need to enable JavaScript to run this app.
导航
使用 HMAC 插件进行 AK/SK 认证
最近更新时间:2024.08.02 11:43:40首次发布时间:2024.08.02 11:43:40

HMAC 插件实现了基于 HMAC 算法为 HTTP 请求生成不可伪造的签名,并基于签名实现身份认证。本文介绍如何使用 HMAC 插件。

注意事项

  • HMAC 插件支持在实例、服务、路由级别的资源中开启和关闭,插件配置的生效优先级为路由 > 服务 > 实例。

  • HMAC 开启后,只有使用合法消费者的 AK/SK 进行签名才可以通过认证及鉴权。

  • AK/SK 在消费者中生成,一个消费者最多具有 1 个 AK/SK。

使用流程

  1. 创建消费者。

  2. 消费者生成 AK/SK。

  3. 客户端生成签名。

  4. 服务端验证签名。

步骤一:创建消费者

  1. 登录 API 网关控制台

  2. 在顶部导航栏,选择目标地域。

  3. 在左侧导航栏选择 消费者管理 > 消费者列表

  4. 在消费者页面,单击 创建消费者

  5. 创建消费者 页面,完成以下配置,然后单击 确定

    配置项说明:

    配置项说明示例值
    所属实例选择消费者所属的实例。instance-doc

    消费者名称

    自定义消费者名称,用于标识该消费者。

    Consumer-doc

    备注可选。您可以根据业务需要选择是否编辑备注内容,例如消费者的用途,便于后期识别。

步骤二:消费者生成 AK/SK

  1. 登录 API 网关控制台

  2. 在顶部导航栏,选择目标地域。

  3. 在左侧导航栏选择 消费者管理 > 消费者列表

  4. 在消费者列表中,单击目标消费者名称,进入消费者详情页面。

  5. 在认证信息区域,单击 生成 AK/SK

  6. 在认证信息中,可以查看已生成的 AK/SK。

步骤三:客户端生成签名

  1. 从原始请求中提取关键数据,得到一个用来签名的字符串 stringToSign

    字段提取内容和规则说明:

    字段是否可为空为空时的字段值说明
    HTTPMethodPOSTHTTP 的方法,全部大写,比如 POST。

    Accept

    \n

    请求中的 Accept 头的值,建议显示设置 Accept Hedaer。部分 HTTP 客户端会将 Accept 默认设置为*/*导致签名失败。

    Content-MD5

    \n

    请求存在 Body 且 Body 为非 Form 形式时计算 Content-MD5 头,可为空。
    生成方式:

    String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
    
    Content-Type\n请求中的 Content-Type 头的值。
    Date\n请求中的 Date 头的值,可为空。

    Headers

    无需加\n

    • 选取指定的 header 参与签名

      • 拼接方式:

        HeaderKey1 + ":" + HeaderValue1 + "\n"\+
        HeaderKey2 + ":" + HeaderValue2 + "\n"\+
        ...
        HeaderKeyN + ":" + HeaderValueN + "\n"
        
      • 如果 HeaderValue 为空,保留 HeaderKey,签名内容如下:

        HeaderKey1 + ":" + "\n"
        
      • 所有参与签名的 Header 的 Key 的集合使用英文逗号分割放到 Key 为 X-Ca-Signature-Headers 的 Header 中,如下:

        x-apig-ca-signature-headers: Headerkey1, HeaderKey2, HeaderKey3
        
    • 以下 Header 不参与 Header 签名计算

      • X-apig-ca-signature

      • X-apig-ca-signature-headers

      • Accept

      • Content-MD5

      • Content-Type

      • Date

    PathAndParameters

    \n

    包含 Path,Query 和 Form 中的所有参数,具体形式如下:

    Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
    
    • Query 和 Form 参数对照 Key 按照字典排序后,使用上面的方式拼接。

    • Query 和 Form 参数为空时,则直接使用 Path,不需要添加。

    • 参数的 Value 为空时,只保留 Key 参与签名,如下:

      Path + "?" + Key1
      
    • Query 和 Form 存在数组参数时(key 相同,value 不同的参数) ,取第一个 Value 参与签名计算。

    1. 查看原始请求。

      原始请求示例如下所示:

      POST/hmactest/test?param1=querystringcontent HTTP/1.1
      host:example.apig.com
      accept:application/json; charset=utf-8
      
      content-type:application/x-www-form-urlencoded; charset=utf-8
      date:Wed, 02 May 2022 12:30:56 GMT+00:00
      X-Top-Account-Id: 20*****346'
      X-Top-Request-Id: 02********415**********000********1b6********8*****d4
      X-Top-Region: cn-north-2
      content-length:33
      
      username=test&password=test1234
      
    2. 从原始请求中提取关键数据。

      HTTPMethod:POST
      Accept:application/json; charset=utf-8
      Content-MD5 :
      Content-Type:application/x-www-form-urlencoded; charset=utf-8
      Date:Wed, 02 May 2022 12:30:56 GMT+00:00
      Headers:
      PathAndParameters:
      
    3. 合成签名字符串 stringToSign

    字符串大小写敏感,字段间用\n间隔。

  2. 使用加密算法和消费者中的consumerSK对提取的签名串stringToSign进行加密处理得到签名sign

    计算方法如下:

    Mac hmacSha256 = Mac.getInstance("HmacSHA256");
    byte[] secretBytes = consumerSK.getBytes("UTF-8");
    hmacSha256.init(new SecretKeySpec(secretBytes, 0, secretBytes.length, "HmacSHA256"));
    byte[] result = hmacSha256.doFinal(stringToSign.getBytes("UTF-8"));
    String sign = Base64.encodeBase64String(result);
    

    加密处理后得到签名sign示例如下:

    POST
    application/json; charset=utf-8
    
    application/x-www-form-urlencoded; charset=utf-8
     Wed, 02 May 2022 12:30:56 GMT+00:00
    X-Top-Account-Id:20*****346
    X-Top-Request-Id:02********415**********000********1b6********8*****d4
    X-Top-Region:cn-north-2
    /hmactest/test?param1=querystringcontent&username=test&password=test1234
    
  3. 将签名相关的所有头加入到原始 HTTP 请求中,得到最终 HTTP 请求。

    POST/hmactest/test?param1=querystringcontent HTTP/1.1
    host:example.apig.com
    accept:application/json; charset=utf-8
    
    content-type:application/x-www-form-urlencoded; charset=utf-8
    date:Wed, 02 May 2022 12:30:56 GMT+00:00
    X-Top-Account-Id: 20*****346'
    X-Top-Request-Id: 02********415**********000********1b6********8*****d4
    X-Top-Region: cn-north-2
    x-apig-ca-key: 用户的AK
    x-apig-ca-signature-method: HmacSHA256
    x-apig-ca-signature-headers: X-Top-Account-Id,X-Top-Request-Id,X-Top-Region
    x-apig-ca-signature: 签名计算结果
    content-length:33
    
    username=test&password=test1234
    

    请求中新增的头内容和说明:

    头内容说明
    x-apig-ca-key用户的 AK
    x-apig-ca-signature-methodHmacSHA256
    x-apig-ca-signature-headersX-Top-Account-Id,X-Top-Request-Id,X-Top-Region
    x-apig-ca-signature签名计算结果

步骤四:服务端验证签名

  1. 从接收到的请求中,提取和客户端一致的字符串 stringToSign 用来签名。

  2. 从接收到的请求中读取 consumerAK,通过 consumerAK 查询到对应的 consumerSK

  3. 使用加密算法和对应的 consumerSK ,对关键数据签名串进行加密处理,得到签名。

  4. 从接收到的请求中读取客户端签名,对比服务器端签名和客户端签名的一致性。