API利用時のセキュリティについて考えてみた
最近は当たり前に使われるようになったAPIですが、改めてAPIのセキュリティについて考えるようになりました。
インフラ目線での考察
簡単なシステム構成を順番に書くと、データベース/API/フロントエンドという3層で表せます。
データベースはできればプライベート環境に配置して、外部ネットワークから直接は接続させないというのが一般的です。
一方でAPIについては2通りが考えられると思います。
APIもプライベート環境に配置できないか
単純には可能です。
ただし、その前提になるのは、APIを利用する機能がブラウザではなく、特定のサーバということになります。
この前提であれば、APIサーバをプライベートに配置して、API利用サーバに限定した接続を許可することで、外部ネットワークから直接の接続ができないようにできます。
一方で、通常のAPI利用はフロントエンドから公開されたページをブラウザが処理し、ブラウザからAPIに接続するというクロスサイトの方式になります。
フロントエンドのサーバ側機能でAPI接続して、必要な情報をレスポンスとしてブラウザに返すというような処理方式であれば、APIサーバの接続制限をフロントエンドサーバに限定することでセキュアにできるかもしれません。
フロントエンドのサーバ機能でAPI接続することにデメリットは?
まず最初に思いつくのはSPAのメリットが享受できなくなる懸念です。
画面遷移や表示制御をブラウザ側に移譲することがSPAのメリットであれば、そのメリットを殺してしまうことになります。
この方法だとモノシリックなシステム構成になるということです。
つまり、そもそもモノシリックなシステム構成なら、APIサーバをプライベートに配置するという考えは「あり」なのかもしれません。
IPでの接続制限を設ける
一方で、セキュリティ強度が高いと思われる方法では、接続元のIPを制限する方法があります。
この方法が使えるのは、接続してくる相手(IP)が分かっている場合に限定されますので、仮に不特定多数のユーザを相手にするようなサービスでは使えません。
企業などで使用するような業務系のアプリケーションであれば、オフィス内の利用であるなど、IPが既知のものであるので有効な方法だと思います。
アプリケーション寄りの目線で考察
アプリケーション目線で考えると最初に出てくるのは「認証」「認可」という対策です。
そもそも、外部ネットワークにAPIを公開するにあたって、何も対策をしなければ、誰でもブラウザ上からAPIを実行するとその結果を受けることができます。
個人情報や企業情報を誰でも見れてしまうのはシステムとしての根源的問題です。
APIキーによる対策
対策として容易に出てくるのは、「APIキー」での対策でしょう。
予めAPI側で特定のキーを発行してもらい、フロントエンド側では、APIリクエスト時にはそのAPIキーをリクエストヘッダに埋め込んで実行するという方法です。
API側はリクエストヘッダのAPIキーを検証して、リクエストを受けることで一定のセキュリティを保ちます。
しかし、リクエストヘッダへの埋め込み情報は、見ることができるので、APIキーを使った「なりすまし」は可能だと言えます。
類似の方法で、ユーザIDとパスワードをAPI側で発行し、それをフロントエンド側でリクエストヘッダに埋め込むという方法もありますが、同様の理由であまりセキュリティ上の強度は強いものではないでしょう。
認証の利用
サービスとして認証を設けることは通常の考え方です。
認証にはユーザIDとパスワードのような普遍的な認証から、MFAなどの認証など様々ですが、ここで注意したいのは認証はあくまで入口でしかないというところです。
Webサービスの認証を通過したということは、そのWebサービスに対しては利用が可能となります。逆に認証を通過しない場合はそのWebサービスの利用ができないということです。
この点で、そのWebサービスに限定すれば有効な認証ではありますが、フロントエンド/バックエンドで別れているモダンな構成であった場合、直接バックエンドであるAPIに対してアクセスすることが可能で、そこに対する認証というわけではありません。
以前として、APIは無防備であることには変わらないという点にご注意ください。
認証とトークンの利用
私が現時点で行き着いている答えになります。
Webサービスとしての認証機能は、実態はバックエンドであるAPIの機能を利用するのが一般的です。
APIの認証機能にもよりますが、認証の結果としてトークンを発行し、認証以外のAPIについてはこのトークンの検証によってしかリクエストを受けないという仕組みであれば、かなりセキュリティ強度は高くなると思います。
フロントエンド側の仕組みとしては、最初の認証APIのOK結果を受信した際に含まれるトークンを取得し、APIインタフェース仕様に準拠してリクエストヘッダ等にこのトークンを埋め込んでリクエストするという方法になります。
前提として、トークンのライフサイクルがセキュリティ強度の鍵となりますので、トークンが永続的なものであれば、そもそもAPIキーと同レベルのものと成り下がることはご理解ください。
OAuthの考え方
別ブログでまとめたOAuthがまさにこのAPIへの認可に関する考え方になると思います。
OAuthに準拠した方法であれば、APIがセルフでトークンを発行する方式でも良いし、別に認可サーバを活用する方式でも可能だと思います。
個人で作るような小規模なアプリケーションの場合は、使用するフレームワークでも認証とトークンを利用したライブラリは公開されているので、その活用でも十分だと思います。
参考
Ruby(Ruby on Rails)
devise(devise-token-auth)というライブラリで、ID/パスワード認証とその後のトークン認証を実装できます。
PHP(laravel)
Breezeというライブラリで、ID/パスワード認証とその後のトークン認証を実装できます。