🗝️

初心者向け: API GatewayのAuthorizerを使ったLambdaとの認証情報連携

2023/10/05に公開

はじめに

JWTを用いてログインしたユーザーに紐づく情報をLambdaから返す、というよくある構成をPyJWTなどのデコードライブラリを使わずに実装します。
本記事はAWS側の実装までになります。

JWTとは何か?

JWT(JSON Web Token)はJSON形式のトークンで、情報を安全にやり取りするために使用されます。トークン内には改ざんを検知するための署名が含まれており、JWTを使用することでクライアントが正当なユーザーであることを確認することができます。

sub値をやりとりするのは危険! 7payの事例から学ぶ教訓

ユーザー情報を連携する際、署名を含むJWTを使わずにsub値(ユーザーを一意に識別する値)を使うことは大変危険です。過去に7payでは、署名を含まずに連携する仕組みだったがために、攻撃者によるなりすましログインを許してしまいました。

7pay外部ID連携の「脆弱性」の構造[1]

連携方法

Cognito→Lambda→API Gatewayの順で説明します。

ステップ1: Cognitoでユーザープールを作成

最初のステップでは、認証機能を提供するCognitoの設定方法を説明します。Cognitoでは、認証に関わる設定を詳細に選択できますが、本記事の論点ではないため基本デフォルトのままとします。

まずは、コンソールでCognitoを検索します。

「ユーザープールを作成」をクリック

サインインに使用する属性として「Eメール」を選択

パスワードポリシーはデフォルトで、多要素認証は「MFAなし」を選択

Eメールプロバイダは「CognitoでEメールを送信」を選択

任意のユーザープール名を入力。ここでは"myUserPool"と入力します。

任意のアプリケーションクライアント名を入力。ここでは"myAppClient"と入力します。

これでCognitoの設定は完了です。

ステップ2: Lambdaで関数を作成

次にLambdaでユーザーIDを示すsub値を取得する方法を説明します。

Lambdaの画面から「関数を作成」をクリック

任意の関数名を入力します。ここでは"myFunction"と入力します。
また、ランタイムはPythonを選択します。

以下のコードを実装し、"Deploy"をクリック

import json

def lambda_handler(event, context):
    user_id = ""
    if "requestContext" in event and "authorizer" in event["requestContext"]:
        user_id = event["requestContext"]["authorizer"]["claims"]["sub"]
        
        #user_idを使った何らかの処理
        
        return {
        'statusCode': 200,
        'body': json.dumps('リクエストに成功しました')
        }
        
    else:
        return {
            'statusCode': 400,
            'body': json.dumps('リクエストに失敗しました')
        }

sub値は以下の部分で取得しています。

if "requestContext" in event and "authorizer" in event["requestContext"]:
	user_id = event["requestContext"]["authorizer"]["claims"]["sub"]

こちらは、次章で説明するAPI Gatewayのオーソライザーで、リクエスト内に含まれるJWTの検証が成功した場合に取得できます。
このsub値を用いてユーザーに特定の権限を付与したり、データベースと連携したりすることができます。

これでLambda関数の作成は完了です。

ステップ3: API GatewayでAPIを作成しオーソライザーを設定

API Gatewayには、リクエストを認証し、認証されたユーザーにアクセスを許可するオーソライザーの機能が備わっています。この機能を利用して、JWTを検証します。以下のステップで設定を行います。

API Gatewayの画面で「APIを作成」をクリック

REST APIの「構築」をクリック

任意のAPI名を入力。ここでは"My API"と入力します。

次にオーソライザーを作成します。
左の「オーソライザー」から、「新しいオーソライザーを作成」をクリック

任意の名前を入力。ここでは"myAuthorizer"と入力します。
タイプは「Cognito」を選択し、Cognitoユーザープールは先ほど作成したものを指定します。

次にAPIのメソッドを作成します。
「アクション」から「メソッドの作成」をクリックし、GETメソッドを作成する。

GETのセットアップをします。
統合タイプは「Lambda」で、Lambdaプロキシ統合の使用にチェックを入れ、Lambda関数は先ほど作成したものを指定します。

最後にAPIにオーソライザーを設定します。
まず「メソッドリクエスト」をクリック

認可を先ほど作成したオーソライザーを指定します。

メソッドリクエストの認可が変更されていることを確認し、「アクション」から「APIのデプロイ」をクリック。ステージ名は任意で入力してください。ここでは"dev"とします。

URLが払い出されました。

まとめ

本記事では、認証機能の利用に必要なCognitoの設定と、API GatewayでJWTを検証する環境の構築及び、Lambdaでのsub値の取得方法を説明しました。
次回の記事では今回実装した環境を使って、Unityでサインアップ・サインイン機能を実装します。

脚注
  1. 狙われた7pay「外部ID連携」の脆弱性の全貌。急遽“遮断”した理由 ↩︎

Discussion