后端签名密钥是由您创建的一对 Key 和 Secret,相当于您给网关颁发了一个账号密码。开启后端签名后 ,API 网关向您后端服务请求时会使用这一对Key和Secret对请求内容进行加签处理,您后端服务可以对网关发送过来的请求做对称加签计算,对比网关的签名和服务器端计算的签名是否一致就可以对网关做身份验证。

概述

  • 创建签名密钥并将签名密钥绑定到 API 即可开启后端签名(请妥善保管此密钥,API 网关会对密钥进行加密存储来保障密钥的安全性)。
  • 创建密钥时需要选择 RegionRegion 一旦选定不能更改,而且密钥只能被绑定到同一个 Region 下的API上。
  • 一个 API 仅能绑定一个密钥,密钥可以被替换和修改。
  • 所有您定义的参数都会参与签名,包括您录入的业务参数、您定义的常量系统参数和 API 网关系统参数(如 CaClientIp 等)。
  • 后端对 API 网关的签名字符串校验后,如果校验失败,建议返回 errorcode = 403;errormessage = “InvalidSignature”。
  • 若您的后端服务为VPC环境,且通过内网对接(专属网络VPC环境开放API),您无需使用后端签名,通道自身是安全的。

读取 API 网关签名方法

网关计算的签名保存在 Request 的 Header 中,Header 名称:X-Ca-Proxy-Signature。

后端 HTTP 服务加签方法

签名计算的详细 demo(JAVA)请参照链接:https://github.com/aliyun/api-gateway-demo-sign-backend-java

签名计算方法步骤如下:

1. 组织参与加签的数据:

String stringToSign=
HTTPMethod + "\n" +         //Method全大写
Content-MD5 + "\n" +        //Content-MD5 需要判断是否为空,如果为空则跳过,但是为空也需要添加换行符 "\n"
Headers +                   //Headers 如果为空不需要添加"\n",不为空的Headers中包含了"\n",详见下面组织Headers的描述
Url

2. 计算签名:

Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] keyBytes = secret.getBytes("UTF-8");  //secret 为绑定到 API 上的签名密钥
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
String sign = new String(Base64.encodeBase64(Sha256.doFinal(stringToSign.getBytes("UTF-8")),"UTF-8"));

补充说明

  • Content-MD5

    Content-MD5 是指 Body 的 MD5 值,只有 HttpMethod 为 PUT 或者 POST 且 Body 为非 Form 表单时才计算 MD5,计算方式为:
    String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
  • Headers

    Headers 指所有参与签名计算的 Header的Key、Value。参与签名计算的 Header 的 Key 从 Request Header 中读取,Key为:"X-Ca-Proxy-Signature-Headers",多个 Key 用英文逗号分割。

  • Headers 组织方法

    先对所有参与签名计算的 Header 的 Key 按照字典排序,然后将 Header 的 Key 转换成小写后按照如下方式拼接:
    String headers = HeaderKey1.toLowerCase() + ":" + HeaderValue1 +"\n"+
     HeaderKey2.toLowerCase() + ":" + HeaderValue2 +"\n"+
     ... +
    HeaderKeyN.toLowerCase() + ":" + HeaderValueN + "\n"
  • Url

    Url指 Path+Query+Body 中 Form 参数,组织方法: 如果有 Query 或 Form 参数则加 ?,然后对 Query+Form 参数按照字典对 Key 进行排序后按照如下方法拼接,如果没有 Query 或 Form 参数,则 Url = Path。

    String url =
     Path +
     "?" +
     Key1 + "=" + Value1 
    + "&" + Key2 + "=" + Value2 +
     ... 
    "&" + KeyN + "=" + ValueN
    说明 1. 这里 Query 或 Form 参数的 Value 可能有多个,多个的时候只取第一个 Value 参与签名计算;2. 只要传递了的参数,签名过程中的等号“=”无论什么情况都需要保留,比如这两个query参数传递时的形式:"path?a=&b",签名时需要写成:"path?a=&b="。
  • 调试模式

    为了方便后端签名接入与调试,可以开启 Debug 模式进行调试,具体方法如下:

    1. 请求API网关的 Header 中添加 X-Ca-Request-Mode = debug。

    2. 后端服务在 Header 中读取 X-Ca-Proxy-Signature-String-To-Sign 即可,因为 HTTP Header 中值不允许有换行符,因此换行符被替换成了 "|"。

    注意:X-Ca-Proxy-Signature-String-To-Sign 不参与后端签名计算。

  • 时间戳校验

    如果后端需要对请求进行时间戳校验,可以在 API 定义中选择系统参数 "CaRequestHandleTime" ,值为网关收到请求的格林威治时间。

密钥泄露 修改替换

当您遇到如下情况:

  • 您的某一个密钥发生了泄露,您可能想要保留该密钥与 API 的绑定关系,但是想要修改密钥的 Key 和 Secret。

  • 当您操作将密钥应用于 API 时,可能该 API 已经绑定了某个密钥,需要替换密钥。

以上两种情况都建议按照下面的流程来操作:

  1. 先在后端同时支持两个密钥:原来的密钥和即将修改或替换的密钥,确保切换过程中的请求能够通过签名验证,不受修改或替换的影响。
  2. 后端配置完备后,完成修改,确定新 Key 和 Secret 生效后再将之前已泄露或废弃的密钥删除。