このシリーズ記事ではREST API を設計するときの指針をまとめていきます。記念すべき第一回目は認証・認可編です。認証と認可
まずはよく概念がごちゃごちゃになってしまう認証と認可の違いについてから。この2つの違いはとても簡単です。ただクラウドを使った場合色んな機能が抽象化され一回のリクエストで同時にその2つが処理されるケースもあるため変わりづらいケースもあります。
認証:リクエスタ(APIを呼び出す側)が誰であるか?APIを呼び出す権限を有しているのか?を判断します。
認可:認証通過後、つまりAPIを呼び出せるリクエスタであると判断された後、どういう操作を許可するか?を定義します。例えば管理者はすべてのデータ操作が可能ですが、一般的な閲覧者は書き込みは許可されず、読み込みのみが許可されます。複数ユーザーが存在しているサイトであれば、リクエスタは自分の権限範囲においてのみデータ読み書きが許可されます。
REST APIで使われる主な認証手法
- APIキー: 固定のAPIキーを使用してアクセスを許可
- JWT (JSON Web Tokens): ユーザーの認証情報に基づいたトークンを発行し、APIアクセスを認証
- OAuth 2.0: 本来認可のプロトコルですが、拡張されている認証プロトコルであるOpenID Connectを用いることで認証認可を同時に実現
APIキー: 固定のAPIキーを使用してアクセスを許可
この方式は固定文字列を用いるため、実装は最も簡単である一方漏洩に対して脆弱です。リクエスタがブラウザやB2Cなど幅広い環境からのアクセスが想定されるアプリケーションには用いない方が良い方式です。多くのクラウドサービスがCLIやツールからのAPI呼び出しに一般的に採用しており、よく使われる方式ですが、採用する場合以下を留意する必要があります。
・アプリケーション毎に個別のAPIキーを発行し使い回しを運用上許可しない。
・定期的なローテーション(ただし機械による乱数をベースとした生成)を行う。頻度は数か月に1度が望ましいです。
またサーバ側で管理するAPIキーは環境変数やAWS Secret Managerを使うなど、ソースコードに埋め込まないことが重要です。
また繰り返しですが、パブリックにアクセス可能なAPIであればこの方式の採用は、なるべくそれ以外の方式を検討することを推奨します。特にWEBサービスであればAPI操作の前にユーザーによるログインというステップが存在しますので、ログイン時にサーバとやり取りした情報をAPI認証に用いる方式が存在しています。それがJWTです。
JWT (JSON Web Tokens): ユーザーの認証情報に基づいたトークンを発行し、APIアクセスを認証
リクエスタがログインを行ったのちサーバとトークンといわれる情報の取り交わしを行います。そのトークンを用いてAPIを呼び出す方法です。トークンの生成や検証は複雑なロジックが必要なので面倒な気もしますがJWTはRFC7519で定義された規格ですのでライブラリなどは豊富に存在しています。トークンに有効期限を設定することで「ログインした後一定時間のみ」API呼び出しが可能になります。
https://ja.wikipedia.org/wiki/JSON_Web_Token
AWSの場合以下のブログで実装方法などが開設されています。
https://aws.amazon.com/jp/blogs/news/routing-in-saas-with-jwt-and-tenant-context/

図中に出ているAmazon Cognito というのはAWSが提供する認証認可サービスです。例えばAPIと連携するウェブサイトにユーザーのログイン画面を作りたい場合、ユーザーログインを外部IDサービスプロバイダー(GoogleやX等)と連携させたい場合、必要な機能を提供してくれる便利なサービスです。
OAuth 2.0: 本来認可のプロトコルですが、拡張されている認証プロトコルであるOpenID Connectを用いることで認証認可を同時に実現
専用の認証サーバが必要になるなど、通常民間企業が提供するには複雑すぎるというデメリットがあります。将来的にアプリへのログインに対して、Google経由での認証を受け付ける等他社が提供している仕組みを用いることが一般的です。

いずれに場合でも、セキュリティのため、認証に用いる情報はHTTPヘッダーに含めて送信し、URLに認証情報を含めないようにします。(セキュリティの観点から、URLパラメータに認証情報を含めないようにする)
認可
認証が行われた後、リクエスタがどの範囲の権限を有してデータ操作を行えるか?が認可のプロセスで判断されます。クラウドの場合これは二段階で制御されます。呼び出されるAPIをホスティングしているAPIそのものが、別のクラウドサービスをどのような権限で呼び出せるのか?という制御がまず基盤レイヤで行われます。これは細かく基盤ごとではなく基盤がホスティングするAPI毎に設定可能です。その上にアプリケーションロジックとしてさらに、認証されたリクエスタの属性に応じて操作の許可を行います。
たとえばhttps:///xxx.com/listというREST APIがあり、Amazon API Gatewayでホスティングされているとします。このAPIはAPI Gatewayの設定(APIにアタッチされるIAMロール)としてデータベースの呼び出し権限を保有しています。一方そのAPIを呼び出したすべてのリクエスタがすべてのデータを閲覧可能とは限りません。これはアプリケーションレイヤで(具体的にはSQLのレベルで)権限を絞る必要があります。
HTTP REST APIにおいて各メソッドに正しいデータ操作リソースの操作権限を付与しておくことは非常に重要です。以下は一般的なデータベースコマンドとのマッピングです。
- GET : Select
- PUT : Insert
- POST : Insert/Update
- PATCH: Update
- DELETE: Delete
例えばGET用APIにInsertの権限を付与していくことは推奨されません。