RESTful 認証とは何を意味し、どのように機能しますか? Google で適切な概要が見つかりません。私の唯一の理解は、URL でセッション キー (remeberal) を渡すということですが、これはひどく間違っている可能性があります。
14 に答える
RESTful クライアント サーバー アーキテクチャで認証を処理する方法については、議論の余地があります。
通常、SOA over HTTP の世界では、次の方法で実現できます。
- HTTPS 経由の HTTP 基本認証。
- クッキーとセッション管理;
- HTTP ヘッダーのトークン (例: OAuth 2.0 + JWT);
- 追加の署名パラメーターを使用して認証を照会します。
ソフトウェア アーキテクチャに合わせて、これらの手法を適応させるか、さらにはうまく組み合わせる必要があります。
各認証方式には、セキュリティ ポリシーとソフトウェア アーキテクチャの目的に応じて、独自の長所と短所があります。
HTTPS 経由の HTTP 基本認証
この最初のソリューションは、標準の HTTPS プロトコルに基づいており、ほとんどの Web サービスで使用されています。
GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
実装は簡単で、すべてのブラウザーでデフォルトで利用できますが、ブラウザーに表示されるひどい認証ウィンドウが持続する (ここには LogOut のような機能はありません)、サーバー側の追加の CPU 消費など、いくつかの既知の欠点があります。ユーザー名とパスワードが (HTTPS 経由で) サーバーに送信されるという事実 (キーボード入力時にパスワードをクライアント側にのみ保持し、サーバーに安全なハッシュとして保存する方が安全です) .
ダイジェスト認証を使用することもできますが、 MiMまたはリプレイ攻撃に対して脆弱であり、HTTP に固有であるため、HTTPS も必要です。
Cookie を介したセッション
正直に言うと、サーバーで管理されるセッションは真のステートレスではありません。
1 つの可能性は、Cookie コンテンツ内のすべてのデータを維持することです。また、設計上、Cookie はサーバー側で処理されます (実際、クライアントはこの Cookie データを解釈しようとさえしません。連続する要求ごとにサーバーに返すだけです)。ただし、この Cookie データはアプリケーションの状態データであるため、純粋なステートレスの世界では、サーバーではなくクライアントが管理する必要があります。
GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123
Cookie の手法自体は HTTP にリンクされているため、真の RESTful ではなく、プロトコルに依存しない必要があります。MiMまたはリプレイ攻撃に対して脆弱です。
トークン (OAuth2) を介して付与
別の方法として、HTTP ヘッダー内にトークンを配置して、要求が認証されるようにすることもできます。これは、たとえばOAuth 2.0 が行うことです。RFC 6749を参照してください。
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
つまり、これは Cookie に非常に似ており、同じ問題があります。ステートレスではなく、HTTP 送信の詳細に依存し、 MiM や Replay を含む多くのセキュリティ上の弱点があるため、HTTPS でのみ使用されます。通常、JWTはトークンとして使用されます。
クエリ認証
クエリ認証は、URI のいくつかの追加パラメーターを介して各 RESTful 要求に署名することで構成されます。この参照記事を参照してください。
この記事では次のように定義されています。
すべての REST クエリは、プライベート資格情報を署名トークンとして使用して、小文字のアルファベット順に並べ替えられたクエリ パラメーターに署名することによって認証される必要があります。署名は、クエリ文字列を URL エンコードする前に行う必要があります。
この手法はおそらくステートレス アーキテクチャとの互換性が高く、簡単なセッション管理 (DB 永続化の代わりにインメモリ セッションを使用) で実装することもできます。
たとえば、上記のリンクからの一般的な URI のサンプルを次に示します。
GET /object?apiKey=Qwerty2010
次のように送信する必要があります。
GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789
署名される文字列は/object?apikey=Qwerty2010×tamp=1261496500
、署名は、API キーのプライベート コンポーネントを使用したその文字列の SHA256 ハッシュです。
サーバー側のデータ キャッシュは常に利用できます。たとえば、私たちのフレームワークでは、URI レベルではなく、SQL レベルで応答をキャッシュします。したがって、この追加のパラメーターを追加しても、キャッシュ メカニズムが壊れることはありません。
JSON と REST に基づく、クライアント サーバー ORM/SOA/MVC フレームワークでの RESTful 認証の詳細については、この記事を参照してください。HTTP/1.1 だけでなく、名前付きパイプまたは GDI メッセージ (ローカル) を介した通信も許可するため、HTTP の特異性 (ヘッダーや Cookie など) に依存せず、真に RESTful な認証パターンを実装しようとしました。
後で注意: URI に署名を追加することは悪い習慣と見なされる可能性があるため (たとえば、http サーバーのログに表示されるため)、リプレイを回避するために適切な TTL などによって緩和する必要があります。しかし、http ログが危険にさらされた場合、より大きなセキュリティ上の問題が発生することは間違いありません。
実際には、OAuth 2.0 の今後のMAC トークン認証は、現在の「Granted by Token」方式に比べて大幅に改善される可能性があります。ただし、これはまだ進行中の作業であり、HTTP 送信に関連付けられています。
結論
REST は HTTP ベースであるだけでなく、実際にはほとんどが HTTP を介して実装されていると結論付ける価値があります。REST は他の通信レイヤーを使用できます。したがって、RESTful 認証は、Google が何を答えようと、単なる HTTP 認証の同義語ではありません。HTTP メカニズムをまったく使用するべきではありませんが、通信層から抽象化する必要があります。また、HTTP 通信を使用する場合、 Let's Encrypt イニシアチブのおかげで、認証スキームに加えて必要な適切な HTTPS を使用しない理由はありません。
このトピックについては、ここの善良な人々によってすでに十分に述べられています。しかし、ここに私の 2 セントがあります。
対話には 2 つのモードがあります。
- ヒューマンツーマシン (HTM)
- マシンツーマシン (MTM)
マシンは共通分母であり、REST API として表現され、アクター/クライアントは人間またはマシンのいずれかです。
現在、真の RESTful アーキテクチャでは、ステートレスの概念は、関連するすべてのアプリケーションの状態 (つまり、クライアント側の状態) をすべての要求で提供する必要があることを意味します。関連するとは、REST API が要求を処理し、適切な応答を提供するために必要なものを意味します。
Skrebbel が上で指摘したように、「ブラウザベース」のヒューマン ツー マシン アプリケーションのコンテキストでこれを考慮すると、これは、ブラウザで実行されている (Web) アプリケーションが、リクエストごとにその状態と関連情報を送信する必要があることを意味します。バックエンドの REST API になります。
これを考慮してください: REST API のデータ/情報プラットフォーム公開アセットがあります。おそらく、すべてのデータ キューブを処理するセルフサービス BI プラットフォームを使用しているでしょう。しかし、(人間の) 顧客が (1) Web アプリ、(2) モバイル アプリ、(3) サード パーティ アプリケーションを介してこれにアクセスできるようにする必要があります。最終的には、MTM の連鎖でさえ HTM につながります。したがって、人間のユーザーは情報チェーンの頂点にとどまります。
最初の 2 つのケースでは、人間とマシンの相互作用のケースがあり、情報は実際には人間のユーザーによって消費されます。最後のケースでは、REST API を使用するマシン プログラムがあります。
認証の概念は全面的に適用されます。REST API が統一された安全な方法でアクセスされるように、これをどのように設計しますか? 私がこれを見る方法は、2つの方法があります:
方法-1:
- そもそもログインはありません。すべてのリクエストでログインが実行されます
- クライアントは、各リクエストで識別パラメータとリクエスト固有のパラメータを送信します
- REST API はそれらを取得し、向きを変え、ユーザー ストア (それが何であれ) に ping を送信し、認証を確認します。
- AUTHが確立されている場合、リクエストにサービスを提供します。それ以外の場合は、適切なHTTPステータスコードで拒否します
- カタログ内のすべての REST API ですべてのリクエストに対して上記を繰り返します
方法-2:
- クライアントは認証要求から始まります
- ログイン REST API は、そのようなすべての要求を処理します。
- 認証パラメーター (API キー、uid/pwd、または選択したもの) を受け取り、ユーザー ストア (LDAP、AD、または MySQL DB など) に対して認証を検証します。
- 検証された場合、認証トークンを作成し、それをクライアント/呼び出し元に返します
- 次に、呼び出し元は、ログアウトするか、リースが期限切れになるまで、他のビジネス REST API への後続のすべての要求とともに、この認証トークン + 要求固有のパラメーターを送信します。
明らかに、方法 2 では、REST API はトークンを有効であると認識して信頼する方法を必要とします。ログイン API が認証検証を実行したため、カタログ内の他の REST API はその「バレット キー」を信頼する必要があります。
これはもちろん、認証キー/トークンを格納して REST API 間で共有する必要があることを意味します。この共有された信頼できるトークン リポジトリは、ローカル/フェデレーションに関係なく、他の組織の REST API が相互に信頼できるようにすることができます。
しかし、私は脱線します。
要点は、すべての REST API が信頼の輪を作成できるように、「状態」(クライアントの認証済みステータスに関する) を維持および共有する必要があるということです。方法 1 であるこれを行わない場合、受信するすべての要求に対して認証行為を実行する必要があることを受け入れる必要があります。
認証の実行は、リソースを大量に消費するプロセスです。uid/pwd の一致をチェックするために、ユーザー ストアに対して受信リクエストごとに SQL クエリを実行することを想像してみてください。または、暗号化してハッシュ マッチを実行する (AWS スタイル)。アーキテクチャ的には、すべての REST API が共通のバックエンド ログイン サービスを使用してこれを実行する必要があると思います。そうしないと、どこにでも認証コードが散らかってしまうからです。大混乱。
レイヤー、レイテンシーが増えます。
さて、Way-1 で HTM に申し込みます。あなたの(人間の)ユーザーは、リクエストごとに uid/pwd/hash などを送信する必要があるかどうかを本当に気にしますか? いいえ、認証/ログインページを毎秒スローして彼女を悩ませない限り。もしそうなら、幸運を祈ります。したがって、ログイン情報をクライアント側のブラウザのどこかに最初に保存し、要求が行われるたびにそれを送信します。(人間の)ユーザーの場合、彼女はすでにログインしており、「セッション」が利用可能です。しかし実際には、彼女はすべての要求で認証されます。
Way-2と同じ。あなたの(人間の)ユーザーは決して気付かないでしょう。だから害はありませんでした。
Way-1 を MTM に適用するとどうなるでしょうか。この場合、これはマシンなので、要求ごとに認証情報を送信するように要求することで、この男をうんざりさせることができます。誰も気にしない!MTM で Way-2 を実行しても、特別な反応は発生しません。そのいまいましいマシン。それはあまり気にしません!
本当に、問題はあなたのニーズに合ったものです。無国籍には代償があります。代価を払って次に進みましょう。純粋主義者になりたいなら、その代償も払って先に進みましょう。
結局のところ、哲学は重要ではありません。本当に重要なのは、情報の発見、プレゼンテーション、消費体験です。人々があなたの API を気に入っているなら、あなたは仕事をしたことになります。
以下は、完全に RESTful な認証ソリューションです。
- 認証サーバーで公開鍵と秘密鍵のペアを作成します。
- 公開鍵をすべてのサーバーに配布します。
クライアントが認証するとき:
3.1. 以下を含むトークンを発行します。
- 有効期限
- ユーザー名 (オプション)
- ユーザー IP (オプション)
- パスワードのハッシュ (オプション)
3.2. 秘密鍵でトークンを暗号化します。
3.3. 暗号化されたトークンをユーザーに送り返します。
ユーザーが API にアクセスするときは、認証トークンも渡す必要があります。
- サーバーは、認証サーバーの公開鍵を使用してトークンを復号化することにより、トークンが有効であることを確認できます。
これはステートレス/RESTful 認証です。
パスワードハッシュが含まれている場合、ユーザーは認証トークンとともに暗号化されていないパスワードも送信することに注意してください。サーバーは、ハッシュを比較することにより、パスワードが認証トークンの作成に使用されたパスワードと一致することを確認できました。HTTPS などを使用した安全な接続が必要です。クライアント側の Javascript は、ユーザーのパスワードを取得し、サーバーの公開鍵で暗号化して、メモリまたは Cookie のいずれかにクライアント側で保存することを処理できます。
正直に言うと、私はここで素晴らしい答えを見てきましたが、誰かがステートレスの概念全体を極端にして独断的にするとき、少し気になります。純粋な OO だけを受け入れたいと思っていた昔の Smalltalk ファンを思い出します。何かがオブジェクトでない場合、それは間違っています。休憩してください。
RESTful なアプローチは、あなたの生活を楽にし、セッションのオーバーヘッドとコストを削減するはずです。賢明なことなので従うようにしてください。意図した利益が得られなくなった場合、それは間違っています。今日の最高の言語の中には、関数型プログラミングとオブジェクト指向の両方を備えているものがあります。
問題を解決する最も簡単な方法が認証キーを Cookie に保存し、それを HTTP ヘッダーで送信することである場合は、それを実行してください。悪用しないでください。セッションが重くて大きくなると悪いことを思い出してください。セッションがすべてキーを含む短い文字列で構成されている場合、大したことは何ですか?
コメントで修正を受け入れることはできますが、サーバーにハッシュの大きな辞書を保持することを単に避けるために、私たちの生活を惨めにする意味が(今のところ)わかりません.
何よりもまず、RESTful Web サービスはSTATELESS (つまり、SESSIONLESS)。したがって、RESTful サービスにはセッションや Cookie の概念が含まれておらず、含まれるべきではありません。RESTful サービスで認証または承認を行う方法は、RFC 2616 HTTP 仕様で定義されている HTTP Authorization ヘッダーを使用することです。すべてのリクエストには HTTP Authorization ヘッダーが含まれている必要があり、リクエストは HTTPS (SSL) 接続を介して送信される必要があります。これは、認証を行い、HTTP RESTful Web サービスで要求の承認を検証する正しい方法です。Cisco Systems で Cisco PRIME Performance Manager アプリケーション用の RESTful Web サービスを実装しました。そして、その Web サービスの一部として、認証/承認も実装しました。
RESTのすべての制約内で実行されるセッションレス認証を指すために一般的に使用されるため、「セッションキー」についてではありません。各リクエストは自己記述的であり、サーバー側のアプリケーション状態なしでリクエストを独自に承認するのに十分な情報を運びます。
これにアプローチする最も簡単な方法は、 RFC 2617の HTTP の組み込み認証メカニズムから始めることです。
2019 年 2 月 16 日の更新
以下で前述したアプローチは、基本的にOAuth2.0の「リソース所有者パスワード資格情報」付与タイプです。これは、起動して実行するための簡単な方法です。ただし、このアプローチでは、組織内のすべてのアプリケーションが独自の認証および承認メカニズムを持つことになります。推奨されるアプローチは、「認証コード」付与タイプです。さらに、以下の以前の回答では、認証トークンを保存するためにブラウザの localStorage を推奨しました。ただし、この目的には Cookie が適切なオプションであると信じるようになりました。この StackOverflow answerで、理由、認証コード許可タイプの実装アプローチ、セキュリティに関する考慮事項などを詳しく説明しました。
REST サービス認証には、次のアプローチを使用できると思います。
- 認証用のユーザー名とパスワードを受け入れるログイン RESTful API を作成します。HTTP POST メソッドを使用してキャッシングを防止し、SSL を使用して転送中のセキュリティを確保 認証が成功すると、API は 2 つの JWT を返します - 1 つのアクセス トークン (短い有効期間、たとえば 30 分) と 1 つのリフレッシュ トークン (長い有効期間、たとえば 24 時間)
- クライアント (Web ベースの UI) は JWT をローカル ストレージに格納し、後続のすべての API 呼び出しで、"Authorization: Bearer #access token" ヘッダーでアクセス トークンを渡します。
- API は、署名と有効期限を確認して、トークンの有効性をチェックします。トークンが有効な場合は、ユーザー (JWT の "sub" クレームをユーザー名として解釈します) がキャッシュ ルックアップを使用して API にアクセスできるかどうかを確認します。ユーザーが API へのアクセスを許可されている場合は、ビジネス ロジックを実行します。
- トークンの有効期限が切れている場合、API は HTTP 応答コード 400 を返します。
- クライアントは、400/401 を受信すると、"Authorization: Bearer #refresh token" ヘッダーのリフレッシュ トークンを使用して別の REST API を呼び出し、新しいアクセス トークンを取得します。
- リフレッシュ トークンを使用した呼び出しを受信したら、署名と有効期限を確認して、リフレッシュ トークンが有効かどうかを確認します。リフレッシュ トークンが有効な場合、DB からユーザーのアクセス権キャッシュをリフレッシュし、新しいアクセス トークンとリフレッシュ トークンを返します。リフレッシュ トークンが無効な場合は、HTTP 応答コード 400 を返します。
- 新しいアクセス トークンと更新トークンが返された場合は、手順 2 に進みます。HTTP 応答コード 400 が返された場合、クライアントは更新トークンの有効期限が切れていると見なし、ユーザーにユーザー名とパスワードを要求します。
- ログアウトするには、ローカル ストレージを消去します
このアプローチでは、30 分ごとにユーザー固有のアクセス権の詳細をキャッシュにロードするというコストのかかる操作を行っています。そのため、アクセス権が取り消されたり、新しいアクセス権が付与されたりした場合、それが反映されるか、ログアウトしてからログインするまでに 30 分かかります。
@skrebel ( http://www.berenddeboer.net/rest/authentication.html ) によって言及された「非常に洞察に満ちた」記事では、複雑ではあるが実際には壊れた認証方法について説明しています。
ログイン資格情報なしで、ページ (認証されたユーザーのみが表示できるようになっている) http://www.berenddeboer.net/rest/site/authenticated.htmlにアクセスしようとする場合があります。
(申し訳ありませんが、答えについてコメントすることはできません。)
REST と認証は単純に混ざり合わないと言えます。REST はステートレスを意味しますが、「認証済み」は状態です。両方を同じレイヤーに配置することはできません。あなたが RESTful の支持者であり、状態に眉をひそめる場合は、HTTPS を使用する必要があります (つまり、セキュリティの問題は別のレイヤーに任せます)。
安らかな認証には、リクエストのパラメーターとして認証トークンを渡すことが含まれると思います。例としては、API による API キーの使用があります。私は、Cookie や http 認証の使用が資格があるとは考えていません。
これを行う方法は次のとおりです。ログインにOAuth2.0を使用する。
OAuthをサポートしている限り、Google以外の認証方法を使用できます。
私の理解からこの質問に答えるには...
システム内のユーザーを実際に追跡または管理する必要がないように、REST を使用する認証システム。これは、HTTP メソッドの POST、GET、PUT、DELETE を使用して行われます。これらの 4 つのメソッドを、データベースの相互作用の観点から、CREATE、READ、UPDATE、DELETE と考えます (ただし、Web では、アンカー タグが現在サポートしているため、POST と GET を使用します)。したがって、POST と GET を CREATE/READ/UPDATE/DELETE (CRUD) として扱うと、達成している CRUD のアクションを推測できる Web アプリケーションのルートを設計できます。
たとえば、Ruby on Rails アプリケーションでは、ログインしているユーザーがhttp://store.com/account/logoutにアクセスした場合、そのページの GET がログアウトを試みているユーザーとして表示されるように、Web アプリを構築できます。 . Rails コントローラーでは、ユーザーをログアウトさせてホームページに戻すアクションを作成します。
ログイン ページで GET を実行すると、フォームが生成されます。ログインページでの POST は、ログイン試行として表示され、POST データを取得してログインに使用します。
私にとっては、データベースの意味にマッピングされた HTTP メソッドを使用してから、セッション ID を渡したりセッションを追跡したりする必要がないことを念頭に置いて認証システムを構築するという習慣です。
私はまだ学んでいます - もし私が間違っていると言ったことを見つけたら、私を訂正してください。ありがとう。