すべてのプロダクト
Search
ドキュメントセンター

API Gateway:hmac-auth

最終更新日:Jan 09, 2025

hmac-authプラグインは、ハッシュベースのメッセージ認証コード (HMAC) アルゴリズムに基づいて、HTTPリクエストの偽造できない署名を生成するために使用されます。 署名は、アイデンティティ認証のために使用される。 このトピックでは、hmac-authプラグインを設定する方法について説明します。

プラグイン型

認証と承認のためのプラグイン。

フィールド

権限付与の設定

項目

データ型

必須 / 任意

デフォルト値

説明

消費者

オブジェクトの配列

対象

-

サービスの呼び出し元。 このフィールドは、リクエストを認証するために使用されます。

date_offset

数値

非対象

-

クライアントの最大時間オフセット (秒) 。 システムはこのフィールドを使用して、リプレイ攻撃を防ぐためにリクエストのDateヘッダーからクライアントのUTC (Universal Time Coordinated) 時間を解析します。 このパラメーターが設定されていない場合、システムはクライアントのUTC時刻を検証しません。

global_auth

文字列の配列

いいえ (インスタンスレベルの設定にのみ必要)

-

このフィールドは、インスタンスレベルでのみ設定できます。 このフィールドがtrueに設定されている場合、認証メカニズムはグローバルに有効になります。 このフィールドがfalseに設定されている場合、認証メカニズムは設定されたドメイン名とルートに対してのみ有効になります。 このフィールドが設定されていない場合、認証メカニズムはドメイン名とルートが設定されていない場合にのみグローバルに有効になります。 これは、古いユーザの使用習慣を考慮したものである。

次の表に、consumersのフィールドを示します。

項目

データ型

必須 / 任意

デフォルト値

説明

キー

String

対象

-

コンシューマーのアクセスキー。

秘密

String

対象

-

署名の生成に使用されるシークレット。

name

String

対象

-

コンシューマーの名前。

(オプション) 許可設定

項目

データ型

必須 / 任意

デフォルト値

説明

許可する

文字列の配列

いいえ (非インスタンスレベルの設定には必須)

-

このフィールドは、ルートやドメイン名などの細かい粒度でのみ設定できます。 一致する条件を満たすリクエストについては、アクセスを許可されるコンシューマーを設定できます。 これにより、詳細な権限制御が実装されます。

重要
  • 許可設定と認証設定はルール内で共存できません。

  • 認証されたリクエストの場合、X-Mse-Consumerフィールドがリクエストヘッダーに追加され、呼び出し元の名前が識別されます。

ルートの認証と承認のグローバル設定

このセクションでは、ゲートウェイの特定のルートまたはドメインのhmac-authプラグインに基づいて認証を有効にする方法の例を示します。 keyフィールドは一意である必要があります。

インスタンスレベルで次のプラグイン設定を適用します。

global_auth: false
consumers: 
- key: appKey-example-1
  secret: appSecret-example-1
  name: consumer-1
- key: appKey-example-2
  secret: appSecret-example-2
  name: consumer-2

route-aおよびroute-bのルートに次の部品設定を適用します。

allow:
- consumer1

次のプラグイン設定を * .example.comおよびtest.comドメイン名に適用します。

allow:
- consumer2
説明
  • この例では、route-aroute-bのルートは、ゲートウェイルートの作成時に指定されたルートです。 クライアント要求がルートの1つと一致する場合、名前consumer1である呼び出し元はゲートウェイにアクセスすることが許可されます。 他の発信者はゲートウェイにアクセスできません。

  • この例では、* .example.comtest.comドメイン名を使用して、リクエストのドメイン名を照合します。 クライアント要求がドメイン名の1つと一致する場合、名前consumer2である呼び出し元はゲートウェイにアクセスすることが許可されます。 他の発信者はゲートウェイにアクセスできません。

ゲートウェイのトラフィックタグプラグインを有効にする

global_auth: true
consumers: 
- key: appKey-example-1
  secret: appSecret-example-1
  name: consumer-1
- key: appKey-example-2
  secret: appSecret-example-2
  name: consumer-2

署名メカニズム

設定の準備

署名の生成と検証に必要な次の資格情報設定を構成する必要があります。

  • key: リクエストヘッダーx-ca-keyで使用されます。

  • secret: リクエスト署名の生成に使用されます。

クライアントで署名を生成する

処理中

署名を生成するために、クライアントは次の手順を実行します。

  1. 元のリクエストからキーデータを抽出し、署名文字列を生成します。

  2. 暗号化アルゴリズムと設定されたシークレットを使用して署名文字列を暗号化し、署名を生成します。

  3. 署名に関連するすべてのヘッダーを元のHTTPリクエストに追加して、最終的なHTTPリクエストを取得します。

署名文字列の抽出

署名を生成するために、クライアントは、HTTP要求から鍵データを抽出し、鍵データを署名文字列に結合する必要がある。 署名文字列の形式は次のとおりです。

HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters

上記のフィールドは署名文字列を構成し、\nで区切られます。 Headersフィールドを空のままにすると、\nは必要ありません。 他のフィールドを空のままにする場合は、\nを保持する必要があります。 署名は大文字と小文字を区別します。

各フィールドを抽出するためのルール:

  • HTTPMethod: POSTなどのリクエストの送信に使用されるHTTPメソッド。 このフィールドの値は大文字です。

  • Accept: リクエスト内のAcceptヘッダーの値。 Acceptヘッダーは空のままにすることができます。 リクエストにAcceptヘッダーを明示的に指定することを推奨します。 Acceptヘッダーが空の場合、一部のHTTPクライアントはAcceptにデフォルト値 */* を使用します。 その結果、署名検証は失敗する。

  • Content-MD5: Content-MD5ヘッダーの値。空のままにすることができます。 この値は、リクエストにフォーム以外のタイプのボディが含まれている場合にのみ計算されます。 次の例は、Java形式のContent-MD5ヘッダーの値を計算するために使用されます。

    String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
  • Content-Type: Content-Typeヘッダーの値。空のままにすることができます。

  • Date: 時間オフセットの検証に使用されるDateヘッダーの値。 date_offsetが指定されていない場合は、このフィールドを空のままにします。

  • ヘッダー: ヘッダーを指定して署名を計算できます。 署名文字列を連結すると、次のルールが適用されます。

    • ヘッダーキーは、最初にアルファベット順にソートされ、次に次のルールに基づいて連結されます。

      HeaderKey1 + ":" + HeaderValue1 + "\n"\+
      HeaderKey2 + ":" + HeaderValue2 + "\n"\+
      ...
      HeaderKeyN + ":" + HeaderValueN + "\n"
    • ヘッダーの値が空の場合は、署名にHeaderKey + ":" + "\n" を使用します。 ヘッダーキーとコロン (:) を保持する必要があります。

    • 署名に使用されるヘッダーキーは、コンマ (,) で区切られ、キーがX-Ca-signature-Headersであるヘッダーに配置されます。

    • X-Ca-signature、X-Ca-Signature-headers、Accept、Content-MD5、Content-Type、Dateのヘッダーを使用して署名を計算することはできません。

  • PathAndParametersフィールドには、すべてのパス、クエリ、およびフォームパラメーターが含まれます。

    Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
説明
  • クエリおよびフォームパラメーターのキーは、最初にアルファベット順にソートされ、次に上記の方法を使用して連結されます。

  • クエリとフォームパラメーターが空の場合、署名情報を追加する必要なしにパスパラメーターを使用できます。

  • 一部のクエリおよびフォームパラメーターが同じキーを持つが値が異なる配列パラメーターである場合、最初の値が署名計算に使用されます。

署名文字列の抽出例

初期HTTPリクエスト:

POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
content-length:33
username=xiaoming&password=123456789

生成された署名文字列:

POST
application/json; charset=utf-8
application/x-www-form-urlencoded; charset=utf-8
Wed, 09 May 2018 13:30:29 GMT+00:00
x-ca-key:203753385
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-signature-method:HmacSHA256
x-ca-timestamp:1525872629832
/http2test/test?param1=test&password=123456789&username=xiaoming

署名を計算する

クライアントがHTTP要求から鍵データを抽出し、署名文字列を生成した後、クライアントは、最終署名を形成するために署名文字列を暗号化および符号化する必要がある。

暗号化プロセスでは、stringToSignは抽出された署名文字列を指定し、secretはプラグイン構成で指定し、signは最終署名を指定します。

Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] secretBytes = secret.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);

要約すると、stringToSignはUTF-8を使用してバイト配列にデコードされます。 バイト配列は、暗号化アルゴリズムを使用して暗号化され、Base64アルゴリズムを使用してエンコードされて署名が生成されます。

署名を追加する

クライアントは、署名検証のためにCloud-native API Gatewayに送信されるリクエストに次のヘッダーを含める必要があります。

  • x-ca-key: 必須のAppKey。

  • x-ca-signature-method: オプションの署名アルゴリズム。 有効な値: HmacSHA256およびHmacSHA1 デフォルト値: HmacSHA256。

  • x-ca-signature-headers: すべての署名ヘッダーのキーのコレクション。オプションです。 キーはコンマ (,) で区切ります。

  • x-ca-signature: 必要な署名。

次の例は、署名付きのHTTPリクエストを示しています。

POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-key:203753385
x-ca-signature-method:HmacSHA256
x-ca-signature-headers:x-ca-timestamp,x-ca-key,x-ca-nonce,x-ca-signature-method
x-ca-signature:xfX+bZxY2yl7EB/qdoDy9v/uscw3Nnj1pgoU+Bm6xdM=
content-length:33
username=xiaoming&password=123456789

サーバー側で署名を確認する

処理中

クライアントから受信した署名を検証するために、サーバーは次の手順を実行します。

  1. リクエストからキーデータを抽出して署名文字列を取得します。

  2. リクエストからキーを読み取り、キーを使用してシークレットを取得します。

  3. 暗号化アルゴリズムとシークレットを使用して署名文字列を暗号化し、署名を取得します。

  4. リクエストからクライアント側の署名を読み取り、サーバー側の署名をクライアント側の署名と比較します。

署名エラーのトラブルシューティング

署名の検証が失敗した場合、システムはサーバー側の署名文字列 (StringToSign) をクライアントに返されるHTTP応答のヘッダーに追加します。 キーはX-Ca-Error-Messageです。 クライアント側の署名文字列 (StringToSign) をサーバー側の署名文字列と比較すると、エラーを特定できます。

2つの値が同じ場合は、署名の計算に使用されるAppSecretを確認します。

HTTPヘッダーは改行をサポートしていません。 署名文字列 (StringToSign) の改行は、数字記号 (#) に置き換えられます。

X-Ca-Error-Message:  Server StringToSign:`GET#application/json##application/json##X-Ca-Key:200000#X-Ca-Timestamp:1589458000000#/app/v1/config/keys?keys=TEST`

エラーコード

HTTPステータスコード

エラーメッセージ

理由

400

無効な署名。

x-ca-signatureリクエストヘッダーには、サーバーで計算された署名と一致しない署名が含まれています。

400

Content-MD5が無効です。

content-md5リクエストヘッダーが無効です。

400

無効な日付。

日付リクエストヘッダーに基づいて計算された時間オフセットが、設定されたdate_offsetを超えています。

401

無効なキー。Invalid Key.

x-ca-keyリクエストヘッダーが提供されていないか、無効です。

401

空の署名。

x-ca-signatureリクエストヘッダーには署名が含まれていません。

403

無許可の消費者。

リクエストの呼び出し元にアクセス権限がありません。

413

リクエストボディが大きすぎます。

リクエストボディのサイズが32 MBを超えています。

413

ペイロードが大きすぎる。

リクエストボディが、ゲートウェイに設定されているDownstreamConnectionBufferLimitsの値を超えています。 パラメータ設定ページで、DownstreamConnectionBufferLimitsの値を増やすことができます。

説明

DownstreamConnectionBufferLimitsの値を増やすと、ゲートウェイのメモリ使用量が大幅に増加します。 この操作は慎重に行ってください。