API Gateway REST APIのリクエスト検証機能を使って、不正なパラメーターのリクエストを弾く

API Gatewayのリクエスト検証機能便利です。
2020.09.09

CX事業本部@札幌の佐藤です。

Amazon API Gateway には リクエストの検証という機能が存在します。これはなにかというと、API のリクエストボディ、リクエストヘッダー、URI を API Gateway 上でチェックし、チェックに失敗した場合は 400 をレスポンスとして返すことができる機能です。この機能を用いることで、後続の Lambda 関数や他の AWS サービスに不要なリクエストが呼ばれないようにすることができます。また、API Gateway 側でリクエストの検証を行うので、アプリケーション側ではよりビジネスロジックの実装に集中することができるようになります。

リクエストパラメーター・クエリストリング・リクエストヘッダについては、必須チェックのみ。リクエストボディについては、JSON Schemaを使って検証を行うことができます。

やってみた

サンプルのAPI Gatewayの作成

コンソールから API Gateway を選択し、API の作成をします。作成する API の一覧が表示されるので、 REST API を選択します。

その後、APIの作成画面に遷移するので、RESTAPIの例 を選択し、インポートをクリックします。これで、サンプルのAPIが作成されます。

リクエストの検証機能を設定する

サンプルのAPIが作成できたので、このAPIに対してリクエストの検証機能を設定してみたいと思います。サンプルAPIとしてPOST /pets パスが作成されているので、それを対象に設定していきます。POST /petsを選択し、メソッドリクエストを選択します。

開くと、 リクエストの検証 という項目が なし になっていると思います。ここに設定します。設定項目としては以下のような内容になっています。

設定項目 意味
クエリ文字列パラメータおよびヘッダーの検証 クエリストリング、パスパラメータ、ヘッダーを検証対象とします
本文、クエリ文字列パラメータ、およびヘッダーの検証 リクエストボディ、クエリストリング、パスパラメータ、ヘッダーを検証対象とします
本文の検証 リクエストボディのみ検証対象とします

今回は全て検証対象とするため、 本文、クエリ文字列パラメータ、およびヘッダーの検証 を選択します。

メソッドリクエストにクエリストリングを設定する

リクエストの検証で、全て検証対象にしたので、一つひとつ設定していきます。まずはクエリストリングです。メソッドリクエストを開くと、 URLクエリ文字列パラメータ という項目の中に、クエリ文字列を追加 というボタンがあるのでそれをクリックします。名前は、適当にmyQueryStringとします。 設定できたら、これを必須項目したいので、必須欄にチェックをいれます。

メソッドリクエストにリクエストヘッダーを設定する

次に、検証対象のリクエストヘッダーを設定します。名前は適当にx-cmsatonaoyaヘッダーとします。これも必須チェックを行うので必須欄にチェックをいれます。

メソッドリクエストにリクエストボディを設定する

最後に検証対象のリクエストボディを設定します。リクエストボディは コンテンツタイプモデル のセットで検証することになります。今回は、JSONをリクエストボディの内容にするので application/json を設定します。また、モデルについてはJSON Schemaの形式で各JSONのプロパティに対してバリデーションを設定することができます。すでにNewPet というモデルが設定されていると思いますので、左側のメニューから モデルを選択します。モデルの中に NewPet があるので、それをクリックすると以下のようなJSON Schemaの定義が出てくると思います。NewPetにはPetTypeが参照されているので、それも見てみます。

NewPet

{
  "type" : "object",
  "properties" : {
    "type" : {
      "$ref":"https://apigateway.amazonaws.com/restapis/ipmvtjk3p4/models/PetType"
    },
    "price" : {
      "type" : "number"
    }
  }
}

PetType

{
  "type" : "string",
  "enum" : [ "dog", "cat", "fish", "bird", "gecko" ]
}

このJSON Schemaの内容からリクエストボディを検証することになります。今回の例だと、リクエストボディはJSON形式で、 typeprice というプロパティを持ち、 type プロパティには、 dog , cat , fish , bird , gecko という文字列のみ許可し、 price はnumber型のみを許可するというバリデーションになります。

デプロイして動作確認

設定が終わったので、APIをデプロイします。API Gatewayは設定を変更した場合デプロイしないと設定が反映されないので、忘れずに行いましょう。リソースメニューに移動して、アクションからAPIのデプロイを選択します。新しいステージを選択しステージ名をdevとします。デプロイをクリックします。デプロイが終わったら、ちゃんとリクエストの検証機能が動作しているかの動作検証を行います。curlでAPIを実行してみます。

curl -X POST "https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/pets?myQueryString=hoge" -H "Content-Type: application/json" -H "x-cmsatonaoya: hoge" -d '{ "type": "dog", "price": 200000  }'
{
  "pet": {
    "type": "dog",
    "price": 200000
  },
  "message": "success"
}

クエリストリングにmyQueryString、ヘッダーにx-cmsatonaoya、リクエストボディには、JSON Schemaに準拠する形でリクエストをしました。うまくリクエストできていそうです。次にリクエストの検証で失敗させてみます。クエリストリングからmyQueryStringを削除してリクエストします。

curl -X POST "https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/pets" -H "Content-Type: application/json" -H "x-cmsatonaoya: hoge" -d '{ "type": "dog", "price": 200000  }'
{"message": "Missing required request parameters: [myQueryString]"}

クエリストリングの myQueryStringは必須としているので、リクエスト検証で弾かれています。次は、ヘッダーもなくしてリクエストしてみましょう。

curl -X POST "https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/pets" -H "Content-Type: application/json" -d '{ "type": "dog", "price": 200000  }'     328ms  水  9/ 9 11:29:18 2020
{"message": "Missing required request parameters: [myQueryString, x-cmsatonaoya]"}

これも弾かれています。最後にヘッダーとクエリストリングを戻してから、リクエストボディを変更してみましょう。リクエストボディのJSONの typedog から snake に変えます。

curl -X POST "https://ipmvtjk3p4.execute-api.ap-northeast-1.amazonaws.com/dev/pets?myQueryString=hoge" -H "Content-Type: application/json" -H "x-cmsatonaoya: hoge" -d '{ "type": "snake", "price": 200000  }'
{"message": "Invalid request body"}

これも Invalid request body として弾かれています。リクエスト検証が動作してそうです。

まとめ

API Gatewayでリクエストの検証機能を使う機会があり、便利な機能でしたのでブログに書きました。誰かの参考になれば幸いです。