為保證API的安全調用,在調用API時阿里云會對每個API請求通過簽名(Signature)進行身份驗證。無論使用HTTP還是HTTPS協議提交請求,都需要在請求中包含簽名信息。

簽名算法

本文介紹函數計算API簽名步驟,SDK中已經實現了簽名算法并對API進行簽名,無需您手動計算。具體信息,請參見SDK列表

對于每一個請求,函數計算服務會根據請求頭部的Authorization字段來校驗是否合法(設置了HTTP觸發器的允許匿名訪問的函數除外)。客戶端須使用與函數計算服務端一致的簽名算法才能通過驗證,對于未包含簽名字段或者簽名錯誤的請求,函數計算將會返回HTTP 403錯誤。

說明 函數計算返回HTTP 403錯誤時,不會產生費用。關于計費的詳細信息,請參見計費概述
signature = base64(hmac-sha256(HTTP_METHOD + "\n" 
                + CONTENT-MD5 + "\n"     
                + CONTENT-TYPE + "\n" 
                + DATE + "\n" 
                + CanonicalizedFCHeaders
                + CanonicalizedResource))

// Authorization字段介紹                
Authorization = "FC " + accessKeyID + ":" + signature            

參數說明如下:

  • HTTP_METHOD:大寫的HTTP方法,例如PUT、GET、POST、DELETE。
  • CONTENT-MD5:請求內容數據的MD5值。如果請求的Header中沒有傳Content-MD5,則此處填入空串。
  • CONTENT-TYPE:請求內容的類型,函數計算的類型是application/json
  • DATE:此次操作的時間,不能為空,支持時區為GMT的RFC1123格式,例如Mon, 02 Jan 2006 15:04:05 GMT
    注意 客戶端需要保證生成的時間與函數計算服務端的時間相差不超過15分鐘,否則函數服務將拒絕此次請求。
  • CanonicalizedFCHeaders:所有以x-fc-為前綴的HTTP頭組成的字符串。生成方式,請參見CanonicalizedFCHeaders
  • CanonicalizedResource:請求的URL的Path,一般是先對收到的Path解碼,再去掉請求的Path里的Params內容。
    • Path的結構為:$api-version/api-path
      • api-version:API版本,目前版本為2016-08-15
      • api-path:訪問各個接口的路徑,例如創建Service為/services,其他Path,請參見API概覽
    • 需要認證的HTTP觸發器與其他請求的CanonicalizedResource不同,下面對這兩種情況分別進行介紹。
      • 需要認證的HTTP觸發器請求:如果有Params,則以回車符\n分隔各個參數,Params中的各個參數key-value對按照字母序進行排序。如果沒有Params則以\n補齊。 例如:
        // 需要認證的HTTP觸發器的URL的真實Path
        /2016-08-15/proxy/service-name/func-name/path-with-%20-space/action?x=1&a=2&x=3&with%20space=foo%20bar
        
        // URL decode后的結果
        /2016-08-15/proxy/service-name/func-name/path-with- -space/action?x=1&a=2&x=3&with space=foo bar
        
        // 需要認證的HTTP觸發器的CanonicalizedResource
        /2016-08-15/proxy/service-name/func-name/path-with- -space/action\na=2\nwith space=foo bar\nx=1\nx=3
        
        // 普通請求的URL的真實Path
        /2016-08-15/service-name/func-name/path-with-%20-space/action?x=1&a=2&x=3&with%20space=foo%20bar
        
        // URL解碼后的結果
        /2016-08-15/service-name/func-name/path-with- -space/action?x=1&a=2&x=3&with space=foo bar
        
        // 普通請求的CanonicalizedResource
        /2016-08-15/service-name/func-name/path-with- -space/action                    
        說明 如果Params里的key對應多個value,即對key-value整體進行排序。
      • 普通請求:首先對收到的Path進行URL解碼,普通請求的CanonicalizedResource會只取到?前面的內容,即舍棄傳入的各個Params
        說明 普通請求是除了需要訪問帶認證的HTTP觸發器的請求外的所有請求。
  • hmac-sha256:需要以您的AccessKey Secret為Key。

    您可以通過以下偽代碼確認簽名的實現方式:

    // 構造字符串的過程
    function composeStringToSign(method, path, headers, queries) {
      var contentMD5 = headers['content-md5'] || '';
      var contentType = headers['content-type'] || '';
      var date = headers['date'];
      var signHeaders = buildCanonicalHeaders(headers, 'x-fc-');
    
      var u = url.parse(path);
      var pathUnescaped = decodeURIComponent(u.pathname);
      var str = `${method}\n${contentMD5}\n${contentType}\n${date}\n${signHeaders}${pathUnescaped}`;
    
      if (queries) {
        var params = [];
        Object.keys(queries).forEach(function (key) {
          var values = queries[key];
          var type = typeof values;
          if (type === 'string') {
            params.push(`${key}=${values}`);
            return;
          }
          if (type === 'object' && values instanceof Array) {
            queries[key].forEach(function (value) {
              params.push(`${key}=${value}`);
            });
          }
        });
        params.sort();
        str += '\n' + params.join('\n');
      }
      return str;
    }
    
    // 使用HMAC-SHA256和Base64計算簽名的過程,其中Source參數為構造出的字符串。
    function signString(source, secret) {
      const buff = crypto.createHmac('sha256', secret)
        .update(source, 'utf8')
        .digest();
      return new Buffer(buff, 'binary').toString('base64');
    }                   

CanonicalizedFCHeaders

完成以下操作,構造阿里云規范頭,操作步驟如下:

  1. 將所有以x-fc-為前綴的請求頭的開頭字段轉換成小寫字母。
  2. 對于每一個字段,生成一個子串${key}:${value}\n ,例如X-Fc-Invocation-Type:Sync轉換成x-fc-invocation-type:Sync\n,這些字段將會按字段名從小到大排序。
    • ${key}:HTTP頭的名稱。
    • ${value}:HTTP頭的值。
  3. 將上述生成的子串連接成一個整串。
    您可以通過以下偽代碼確認簽名的實現方式:
    // javascript
    // prefix = 'x-fc-'
    function buildCanonicalHeaders(headers, prefix) {
        var list = [];
        var keys = Object.keys(headers);
    
        var fcHeaders = {};
        for (var i = 0; i < keys.length; i++) {
            var key = keys[i];
    
            var lowerKey = key.toLowerCase().trim();
            if (lowerKey.startsWith(prefix)) {
                list.push(lowerKey);
                fcHeaders[lowerKey] = headers[key];
            }
        }
        list.sort();
    
        var canonical = '';
        for (var _i = 0; _i < list.length; _i++) {
            var _key = list[_i];
            canonical += `${_key}:${fcHeaders[_key]}\n`;
        }
    
        return canonical;
    }            
    Authorization可由上文計算得出的signature構造出來,構造方法如下:
    Authorization = "FC " + accessKeyID + ":" + signature