質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.69%

APIの認証方法と公開について

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 3,276

twin_bird

score 222

jsonを返すAPIをつくっています。

APIの認証には、ヘッダにトークンを投げ、サーバーサイドのミドルウェアでトークンをチェックするという方式を取っています。

公開を想定したAPIなのですが、セキュリティについて分からないところがあります。

このAPIを自アプリケーション内で使用する際、アドミン用のトークンをヘッダに含めているのですが、それだとアドミン用のトークンを公開してしまうことになり、APIに認証を設ける意味がないと気づきました。

APIを公開する際には認証を必要としたいので、利用するユーザーそれぞれにAPIトークンを発行したいのですが、自アプリケーション内でAPIを安全に利用するにはどういう対策がありますでしょうか?

公開用とアドミン用のAPIを別に作成する必要があるのでしょうか??

 追記

追記: バックにはLaravel、フロントはReactを使っています。自作APIを利用するときは、基本的にはReactでAPIを叩いています。

追記: 皆様、有益な回答ありがとうございます。ググっても中々実装例が出てこなかったのでとても助かります。ただ、幅広い意見をお伺いしたいので今しばらく回答を募集中のままにさせていただきます。

 改めて質問内容を整理します。

Laravelでアプリケーションを開発しており(以下、Laravel Appとします。Wantedlyのようなサービスです。)、「Laravel App内で使用すること」と「外部のクライアントに利用してもらうこと(外部クライアントが開発している別のアプリケーション等に利用してもらう、など)」を目的としたAPIを作っています。

このAPIを利用するには、ヘッダにLaravel Appが発行するユーザー(Laravel Appの利用者かつ登録者)それぞれが保持するAPI Tokenを含めてPOSTすることでLaravel APPのミドルウェアが認証処理を行い、レスポンスを返してくれます。

外部のクラアイントがAPIを利用する分には、このAPI Tokenでの認証方法で良いと思います。(回答者の方のご指摘通り、Tokenのチェック方法に留意する点はまだありますが・・)

しかし、この認証方法を設けてしまうと、Laravel App自身がAPIを使用することが難しくなってしまいます。
例えば、Laravel Appが自身がAPIを利用するためのアドミン用のAPI Tokenを用意しても、ヘッダ情報にAPI Tokenを含める必要があるため、Larave Appを利用する全てのユーザーにアドミン用のAPI Tokenが公開されてしまいます。

上記の利用目的において、APIの認証方法はどのようにすべきでしょうか?

 考えている方法

  • 公開用と内部で使用する用でAPIを分ける。内部で使用する用は非公開にする。

  • アドミン用のAPI Tokenを利用せず、ユーザー(Laravel Appの利用者かつ登録者)のAPI Tokenを利用させる。本来、API Tokenは外部の別のアプリケーションの開発等に使用してもらうためのものを想定していたが、Laravel Appを利用する際も使用する仕様にする。
    API TokenはLaravel Appに登録した時に自動で発行、いつでもリフレッシュ可能なものとする。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

クライアント側のJavaScriptファイルなどにあらかじめトークンをハードコーディングし、それを配布するともちろんダメです。

認証(ログイン)機能を設け、認証に成功したらトークンを発行し、トークン内にユーザ情報などを埋め込み、サーバ側で秘匿な状態にしてある鍵で署名し、SSL通信でやりとりすれば、ユーザー側での改ざんと通信経路上におけるトークンの流出は防げます。具体的にはJWT+SSL通信でよいのではないでしょうか。

ただしそのようにしてもクライアント側に渡った後のトークンの盗難は防げません。(たとえばPCロックせずに離籍したときに他人がブラウザ開いてローカルストレージに保存してあるトークンを盗むなど)
有効期限を設定し、期限が切れたら再ログインしてもらう…ということになります。リフレッシュトークンを発行してもそれが盗まれたら…と考えるとキリがありません。

過去の私の回答でも考察してるのでこちらもどうぞ。
また私もこの辺り色々考えすぎて頭を痛くした経験がありますので、有識者の方の回答を私も伺ってみたいところです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/22 15:23

    回答ありがとうございます。
    JWTというのは知らなかったです。調べてみます。
    過去の投稿も拝見しました。
    トークンの受け渡しのセキュリティについて勉強不足な気がしたので、調べてみます!

    キャンセル

+2

認証の安全性を考えるときには鍵の運用管理方法を考える必要があります。
ですから、API を呼ぶのが Web UI (=ブラウザやハイブリッドアプリ)からなのか、何かの自動処理システムからなのかによって話が異なります。

Web UI の場合であれば、通常の Web 認証を行い、その Cookie で認証すべきでしょう。毎回ログイン手続きがめんどくさいというクレームがでるのであれば、Cookie の無通信タイムアウトを長めにする手もあります。

UI ではない、システムから呼ばれるのであれば、利用者(あるいはクライアント側のシステム管理者)毎にトークンを発行する必要があるでしょう。そのトークンを他者に盗まれないようにするのは利用者の責任となります。また、利用者はそのトークンが盗まれた可能性が出た時点で速やかにサーバのシステム管理者に報告するよう約束してもらう必要があります。APIの提供側はトークンが盗まれた可能性がある場合に、そのトークンだけを速やかに無効にする機能が必要です。

また、API 呼び出し時にトークンをそのまま付けると、通信経路上やブラウザのキャッシュメモリから一個でも盗まれると(あってはならないことですが)、ずっと使えてしまうので、トークンをそのまま渡すのではなく、APIの内容に発信時刻、ソルトを添えてダイジェストメッセージを作成し、これをトークンの値でハッシュして署名します。サーバ側で同じ操作を行い、同じハッシュ値であればそれを作った人がそのトークンを持っていることが担保できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/22 15:21

    回答ありがとうございます。
    色々混乱していて回答内容をすぐに飲み込めなかったのですが、Cookieで認証させれば解決する気がしました!
    API呼び出し時の工夫は見逃していたのでこちらも見直してみようと思います。

    キャンセル

check解決した方法

+1

mit0223さんの回答が解決方法に近かったのですが、自分なりに解釈して解決したので、こちらに解決方法を投稿します。

アプリケーション内部でのapiの利用方法については、ログイン手続きと同じCookieを利用した認証方法を取りました。
Laravelのログインチェックのやり方に沿って、ミドルウェア内でログインチェックを行うようにしました。

外部からの利用に関しては、API Tokenをヘッダに含める方式を継続して採用することにしました。こちらは安全性をより高める為の実装(署名の工夫など)も検討してみようと思います。

なお、API Tokenによる認証もミドルウェアで行うように実装しました。
従ってミドルウェアではCookie認証とAPI Tokenによる認証のどちらを利用するかの条件分岐を含くめました。
結果的に内部からAPIを叩く必要がなくなりました。

よくよく考えれば単純でシンプルな解決方法でした笑
APIを叩くことにとらわれていましたw

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.69%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる