設計 - RESTfulな認証




restとは (10)

@skrebel( here )に言及されている「非常に洞察力の高い」記事は、畳み込まれているが本当に壊れている認証方法について説明しています。

ログイン資格情報を持たないページ(認証されたユーザーのみが閲覧可能とする) http://www.berenddeboer.net/rest/site/authenticated.html

(申し訳ありませんが私は答えにコメントすることはできません。)

私はRESTと認証が混ざり合っていないと言っています。 RESTはステートレスを意味しますが、「認証済み」は状態です。 両方を同じレイヤーに置くことはできません。 あなたがRESTfulな主張者であり、州を嫌うなら、HTTPSに行く必要があります(つまり、セキュリティの問題を別の層に任せる)。

RESTful認証とは何を意味し、どのように機能しますか? 私はGoogleの良い概観を見つけることができません。 私の唯一の理解は、あなたがURLにセッションキー(remeberal)を渡すことですが、これはひどく間違っている可能性があります。


RESTfulなクライアント - サーバー・アーキテクチャーでの認証の処理方法は議論の余地があります。

一般的には、HTTP経由のSOAの世界では、

  • HTTP基本認証over HTTPS;
  • クッキーとセッション管理。
  • HTTPヘッダーのトークン(例: OAuth 2.0 + JWT)。
  • 追加の署名パラメータで認証を照会します。

これらのテクニックを適応させたり、よりよく混合したりして、ソフトウェアのアーキテクチャに合わせる必要があります。

各認証方式は、セキュリティポリシーとソフトウェアアーキテクチャの目的に応じて、独自のPROとCONを持っています。

HTTP基本認証over HTTPS

この最初のソリューションは、標準のHTTPSプロトコルに基づいており、ほとんどのWebサービスで使用されています。

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

実装が簡単で、すべてのブラウザでデフォルトで利用可能ですが、ブラウザに表示されるひどい認証ウィンドウ(ここではLogOutのような機能はありません)、サーバー側の追加CPU消費量、ユーザー名とパスワードがサーバーに送信される(HTTPS経由で)(パスワードをクライアント側のみに、キーボード入力中に保存し、サーバー上の安全なハッシュとして保管することがより安全でなければならない) 。

ダイジェスト認証を使用することもできますが、 MiM攻撃またはReplay攻撃に対して脆弱でHTTPに固有のものであるため、HTTPSも必要です。

クッキーによるセッション

正直言って、サーバー上で管理されるセッションは、本当にステートレスではありません。

1つの可能性は、クッキーコンテンツ内のすべてのデータを維持することです。 そして、設計上、クッキーはサーバー側で処理されます(クライアント、実際には、このクッキーデータを解釈しようとしません。それぞれの要求に対してサーバーに戻すだけです)。 しかし、このクッキーデータはアプリケーションの状態データなので、クライアントは純粋なステートレスな世界でサーバーではなくサーバーを管理する必要があります。

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

クッキーの技術自体はHTTPにリンクされているので、実際にはRESTfulではありません。プロトコルに依存しないIMHOでなければなりません。 MiM攻撃またはReplay攻撃に対して脆弱です。

トークン(OAuth2)経由で付与

別の方法として、要求が認証されるようにHTTPヘッダー内にトークンを置く方法があります。 これは、たとえばOAuth 2.0の機能です。 RFC 6749を参照してください:

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

要するに、これはクッキーと非常によく似ており、ステートレスではなく、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&timestamp=1261496500あり、署名はAPIキーの専用コンポーネントを使用するその文字列のSHA256ハッシュです。

サーバー側のデータキャッシングはいつでも利用できます。 たとえば、私たちのフレームワークでは、レスポンスをURIレベルではなくSQLレベルでキャッシュします。 したがって、この余分なパラメータを追加しても、キャッシュメカニズムが破られることはありません。

JSONとRESTに基づいた、クライアント/サーバーのORM / SOA / MVCフレームワークでのRESTfulな認証の詳細については、 この記事を参照してください。 HTTP / 1.1だけでなく、名前付きパイプやGDIメッセージ(ローカル)を介して通信できるようになったので、HTTPの特殊性(ヘッダやクッキーなど)に頼らず、真にRESTfulな認証パターンを実装しようとしました。

後で注意してください :URIにシグネチャを追加することは悪い習慣と見なすことができます(たとえば、httpサーバのログに表示されるため)。これは、リプレイを避けるために適切なTTLなどによって緩和する必要があります。 しかし、あなたのHTTPログが漏洩した場合、あなたは確かに大きなセキュリティ上の問題を抱えています。

実際には、OAuth 2.0の今後のMACトークン認証は 、「トークンによって許可された」現在のスキームに関して劇的に改善される可能性があります。 しかし、これはまだ進行中の作業であり、HTTP転送に結びついています。

結論

RESTはHTTPベースで実装されているだけでなく、実際にはHTTP経由で実装されている場合でも、RESTはHTTPベースであると結論づける価値があります。 RESTは他の通信レイヤーを使用できます。 だから、RESTfulな認証は、Googleが何を答えても、HTTP認証の同義語だけではありません。 HTTPメカニズムをまったく使用しないでください。ただし、通信レイヤーから抽象化される必要があります。 また、HTTP通信を使用する場合は、 Let's Encryptイニシアチブのおかげで、適切なHTTPSを使用しない理由はありません。これは、認証スキームに加えて必要です。


任意のWebアプリケーションのセキュリティ保護に有効なヒント

アプリケーションのセキュリティを確保する場合は、HTTPの代わりにHTTPSを使用することから始める必要があります。これにより、ユーザーとユーザーとの間で安全に通信できるようになり、データの盗聴を防ぐことができます機密を交換した

JWT(JSON Webトークン)を使用してRESTful APIを保護することができます。これはサーバー側セッションと比較して多くの利点がありますが、そのメリットは主に次のとおりです。

1-スケーラビリティの向上:APIサーバーは各ユーザーのセッションを維持する必要がなくなります(セッション数が多い場合は大きな負担になります)

2つのJWTは自己完結型であり、ユーザーの役割を定義するクレームがあります(例えば、JWTは有効ではありません)

3つのロードバランサ間での処理が容易で、複数のAPIサーバを使用してセッションデータを共有したり、セッションを同じサーバにルーティングする必要がなくなり、JWTを使用した要求が認証されると承認された

4 - あなたのDBへの負荷を軽減するだけでなく、リクエストごとにセッションIDとデータを絶えず保存して取得する必要もありません

5-強力な鍵を使用してJWTに署名すると、JWTを改ざんすることはできません。したがって、ユーザーセッションを確認することなく、要求に応じて送信されたJWT内のクレームを信頼できますあなたはJWTをチェックすることができます。そして、あなたはこのユーザーが誰が&何を行えるかを知るように設定されています。

多くのライブラリは、ほとんどのプログラミング言語でJWTを作成および検証する簡単な方法を提供します。たとえば、node.jsで最も人気のあるjsonwebtoken 1つはjsonwebtoken

REST APIは一般的にサーバーをステートレスに保つことを目的としているため、JWTは、サーバーがユーザーセッションを追跡しなくても、各リクエストが自己完結型の認可トークン(JWT)で送信されるため、サーバーはステートフルなので、ユーザーとその役割を覚えていますが、セッションも広く使用されており、必要に応じて検索することができます。

注意すべき重要な点の1つは、HTTPSを使用してJWTをクライアントに安全に配信し、安全な場所(たとえばローカルストレージなど)に保存する必要があることです。

このリンクから JWTの詳細を知ることができます


すでにここでは良い人たちによってこの話題について言われています。 しかしここに私の2セントです。

相互作用には2つのモードがあります。

  1. ヒューマンツーマシン(HTM)
  2. マシンツーマシン(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:

  1. まず、ログインはありません。 すべてのリクエストがログインを実行する
  2. クライアントは、その識別パラメータ+要求ごとに要求固有のパラメータを送信します
  3. REST APIはそれらを受け取り、向きを変えて、ユーザーストアに(何でも)pingを実行し、認証を確認します
  4. 認証が確立されている場合は、要求を処理します。 それ以外の場合は、適切なHTTPステータスコードで拒否します。
  5. カタログ内のすべてのREST APIのリクエストごとに上記を繰り返します。

ウェイ2:

  1. クライアントは認証要求で始まります
  2. ログインREST APIは、そのようなすべてのリクエストを処理します
  3. 認証パラメータ(APIキー、uid / pwdなど)を取得し、ユーザーストア(LDAP、AD、またはMySQL DBなど)に対して認証を検証します。
  4. 検証された場合は、認証トークンを作成してクライアント/呼び出し元に返します
  5. その後、呼び出し元は、ログアウトするまで、またはリースが終了するまで、この認証トークン+他のビジネスREST APIへのすべての後続要求で特定のparamsを要求します

明らかにWay-2では、REST APIはトークンを認識し、それを有効なものとして信頼する方法を必要とします。 ログインAPIは認証確認を実行したため、カタログの他のREST APIによって「バレーキー」を信頼する必要があります。

これは、もちろん、認証キー/トークンを保存し、REST API間で共有する必要があることを意味します。 この共用された信頼できるトークン・リポジトリは、ローカル/フェデレーションされたもので、他の組織のREST APIが互いに信頼できるようにすることができます。

しかし、私は逃げる。

要点は、すべてのREST APIが信頼のサークルを作成できるように、「状態」(クライアントの認証済みステータスに関する)を維持し共有する必要があることです。 私たちがこれをやっていない、つまりWay-1の場合は、入ってくるすべての/すべての要求について認証の行為を実行しなければならないということを認めなければなりません。

認証を実行することは、リソースを大量に消費するプロセスです。 すべての着信要求に対して、uid / pwdの一致をチェックするためにユーザーストアに対してSQLクエリを実行するとします。 または、ハッシュ・マッチ(AWSスタイル)を暗号化して実行します。 そして、アーキテクチャ上、すべてのREST APIは共通のバックエンド・ログイン・サービスを使用してこれを実行する必要があります。 なぜなら、そうしなければ、どこにでも認証コードを捨てるからです。 大きな混乱。

レイヤーが増えるほどレイテンシが増えます。

今、Way-1に乗り、HTMに応募してください。 uid / pwd / hashを送信する必要があるかどうか、あなたの(人間の)ユーザは本当に気にしますか? いいえ、あなたが毎秒auth / loginページを投げることで彼女を気にしない限り。 あなたがいるならば、顧客を持つことを幸運。 ですから、ログイン情報をクライアントサイドのどこかにブラウザに保存して、最初から入力してください。 (人間の)ユーザの場合、彼女はすでにログインしており、「セッション」が利用可能です。 しかし、実際には、彼女はあらゆる要求に対して認証されています。

Way-2と同じです。 あなたの(人間の)ユーザーは決して気づかないでしょう。 だから害はありませんでした。

Way-1をMTMに適用するとどうなりますか? この場合、そのマシンであるため、毎回のリクエストで認証情報を送信するように要求することで、この人から地獄を救うことができます。 誰も気にしない! MTMでWay-2を実行しても、特別な反応は起こりません。 それはそのマシンです。 あまり気にしないだろう!

だから本当に、あなたの必要に合ったのが問題です。 無国籍者には支払うべき代価があります。 価格を払い、次に進む。 あなたが純粋主義者になりたいならば、それに代わって価格を払い、次に進む。

結局のところ、哲学は重要ではありません。 本当に重要なのは情報発見、プレゼンテーション、消費体験です。 人々があなたのAPIを愛しているなら、あなたはあなたの仕事をしました。


本当に完全にRESTfulな認証ソリューションです:

  1. 認証サーバに公開鍵/秘密鍵のペアを作成します。
  2. すべてのサーバーに公開鍵を配布します。
  3. クライアントが認証するとき:

    3.1。 次のトークンを発行します。

    • 有効期限
    • ユーザー名(オプション)
    • ユーザーIP(オプション)
    • パスワードのハッシュ(オプション)

    3.2。 トークンを秘密鍵で暗号化します。

    3.3。 暗号化されたトークンをユーザーに送り返します。

  4. ユーザーがAPIにアクセスする際には、認証トークンも渡す必要があります。

  5. サーバーは、認証サーバーの公開キーを使用してトークンを復号化することによって、トークンが有効であることを検証できます。

これは、ステートレス/ RESTfulな認証です。

パスワードハッシュが含まれている場合、ユーザーは認証トークンとともに暗号化されていないパスワードも送信することに注意してください。 サーバーは、ハッシュを比較して認証トークンの作成に使用されたパスワードとパスワードが一致しているかどうかを検証できます。 HTTPSのようなものを使った安全な接続が必要です。 クライアントサイドのJavascriptは、ユーザのパスワードを取得し、メモリまたはクッキーのいずれかにクライアント側を格納し、サーバの公開鍵で暗号化される可能性があります。


正直言って私はここで大きな答えを見たことがありますが、少し気になるのは、ステートレスな概念全体を独断的な極端なものにするときです。 それは純粋なオブジェクト指向を受け入れることを望んでいた古いスモールトークのファンを思い出させ、何かがオブジェクトでない場合は間違っていると思います。 私に休憩を与えてください。

RESTfulなアプローチは、あなたの人生をより簡単にし、セッションのオーバーヘッドとコストを削減し、それを実行することを賢明なものにしてみることになっていますが、極限まで規律(あらゆる規律/ガイドライン)それが意図した利益をもはや提供しなくなり、あなたは間違っています。 今日の最良の言語の中には、関数型プログラミングとオブジェクト指向の両方があります。

あなたの問題を解決する最も簡単な方法は、認証キーをクッキーに格納してHTTPヘッダーに送信してから、悪用しないでください。 セッションが重く大きくなったときにセッションが悪いことを忘れないでください。すべてのセッションがキーで構成された短い文字列であれば、大きな問題は何ですか?

私はコメントの修正を受け入れるために開いているが、私たちの生活を悲惨なものにして、単にサーバーのハッシュの大きな辞書を保持しないようにするという点を(今のところは)見ていない。


私は、次のアプローチをRESTサービス認証に使用できると考えています。

  1. 認証のためのユーザー名とパスワードを受け入れるログインRESTful APIを作成します。HTTP POSTメソッドを使用して転送中のセキュリティを保護します。認証に成功すると、APIは1つのアクセストークン(短い有効性、30分など)と1つのリフレッシュトークン(長い有効性、たとえば24時間)
  2. クライアント(ウェブベースのUI)はJWTをローカルストレージに格納し、その後の各APIコールでアクセストークンを「Authorization:Bearer #access token」ヘッダーに渡します
  3. APIは、署名と有効期限を確認することによって、トークンの有効性をチェックします。トークンが有効な場合、ユーザー(JWTの「サブ」クレームをユーザー名と解釈します)がキャッシュルックアップを使用してAPIにアクセスできるかどうかを確認します。ユーザーがAPIにアクセスする権限を持っている場合は、ビジネスロジックを実行します
  4. トークンが期限切れになっている場合、APIはHTTP応答コード400を返します
  5. 400/401を受信したクライアントは、新しいアクセストークンを取得するために、「Authorization:Bearer #refresh token」ヘッダーにリフレッシュトークンを持つ別のREST APIを呼び出します。
  6. リフレッシュトークンでコールを受信すると、署名と有効期限を確認して、リフレッシュトークンが有効かどうかを確認します。リフレッシュトークンが有効な場合は、DBからユーザーのアクセス権キャッシュをリフレッシュし、新しいアクセストークンとリフレッシュトークンを返します。リフレッシュトークンが無効な場合は、HTTP応答コード400を返します
  7. 新しいアクセストークンとリフレッシュトークンが返された場合は、手順2に進みます。HTTP応答コード400が返された場合、クライアントはリフレッシュトークンが期限切れであるとみなし、ユーザーからのユーザー名とパスワードを要求します
  8. ログアウトの場合は、ローカルストレージをパージします。

このアプローチでは、30分ごとにユーザー固有のアクセス権の詳細をキャッシュにロードするという高価な操作を実行しています。したがって、アクセスが取り消されたり、新しいアクセスが許可された場合、反映するまでに30分かかります。


私は熱心に "HTTP認証"を叫んでいる人々がRESTを使って(マシンツーマシンWebサービスの代わりに)ブラウザベースのアプリケーションを作成しようとしたのかどうか疑問に思っています(犯罪は意図されていません - 。

ブラウザで表示するHTMLページを生成するRESTfulなサービスでHTTP認証を使用して見つかった問題は次のとおりです。

  • ユーザーは通常、非常にユーザーに不愉快な、醜いブラウザー製のログインボックスを取得します。 パスワード検索、ヘルプボックスなどを追加することはできません。
  • ログアウトまたは別の名前でログインすることは問題です。ブラウザは、ウィンドウを閉じるまで、認証情報をサイトに送信し続けます
  • タイムアウトが難しい

これらの1つ1つのポイントを対処する非常に洞察力の高い記事はhereにありhere 、ブラウザ固有のJavaScriptのハッキングや回避策の回避策などがたくさんあります。 したがって、それも順方向互換性がないので、新しいブラウザがリリースされると、一定のメンテナンスが必要になります。 私はそれがきれいで明確なデザインであるとは考えていませんし、余分な仕事や頭痛のように感じていますので、私の友人にRESTバッジを熱狂的に見せることができます。

私はクッキーが解決策だと信じています。 しかし、待って、クッキーは悪いですね。 いいえ、そうではありません。クッキーがよく使われる方法は悪です。 クッキー自体は、ブラウザーがブラウズ中に追跡するHTTP認証情報のように、クライアント側の情報の一部にすぎません。 そして、クライアント側の情報のこの部分は、HTTP認証情報と同様に、リクエストごとにサーバーに送信されます。 概念的には、唯一の違いは、クライアント側の状態のこの部分の内容が、その応答の一部としてサーバーによって判断できることです。

セッションをRESTfulなリソースにするだけで、以下のルールが適用されます。

  • セッションは、キーをユーザIDにマップします(タイムアウトの場合は最後のアクション・タイムスタンプも可能です)
  • セッションが存在する場合は、そのキーが有効であることを意味します。
  • ログインとは/セッションへのPOSTing、新しいキーがクッキーとして設定されていることを意味します
  • ログアウトとは、DELETEing / sessions / {key}を意味します(POSTが過負荷で、覚えておいて、私たちはブラウザで、HTML 5はまだまだです)
  • 認証は、リクエストごとにCookieとしてキーを送信し、セッションが存在し、有効であるかどうかをチェックすることによって行われます

HTTP認証との唯一の違いは、認証キーがサーバーによって生成され、クライアントが入力した資格情報からコンピューティングを計算するのではなく、クライアントに送信することです。

converter42では、httpsを使用する際には、Cookieに安全なフラグが設定されていて、認証情報が安全でない接続で送信されないようにすることが重要です。 大きなポイントは、それを自分で見ていない。

私はこれがうまくいく十分な解決策だと感じていますが、私はこのスキームの潜在的な穴を特定するのにセキュリティ専門家では不十分であることを認めなければなりません。何百ものRESTfulでないWebアプリケーションが本質的に同じログインプロトコル(PHPでは$ _SESSION、Java EEではHttpSessionなど)。 クッキーヘッダーの内容は、サーバー側のリソースに対処するために使用され、受け入れ言語が翻訳リソースなどにアクセスするのと同じように使用されます。 私はそれが同じだと感じますが、他の人はそうではないでしょうか? あなたはどう思いますか?



私は安静な認証は、要求の中のパラメータとして認証トークンを渡すことを必要とすると考えています。apikeysをapiで使用する例があります。私はクッキーまたはhttpの認証の使用が適格とは思わない。







rest-security