web-dev-qa-db-ja.com

RESTful Webサービス-他のサービスからのリクエストを認証する方法は?

ユーザーがアクセスする必要があるRESTful Webサービスだけでなく、他のWebサービスとアプリケーションも設計しています。すべての着信要求を認証する必要があります。すべての通信はHTTPSを介して行われます。ユーザー認証は、ユーザーが提供する/ sessionリソースに(SSL接続を介して)ユーザー名とパスワードをPOSTすることで取得した認証トークンに基づいて機能しますサービス。

Webサービスクライアントの場合、クライアントサービスの背後にエンドユーザーなしがあります。要求はスケジュールされたタスクによって開始されます。 、イベントまたはその他のコンピューター操作。接続サービスのリストは事前にわかっています(明らかに、私は推測します)。 他の(Web)サービスからのこれらのリクエストをどのように認証する必要がありますか認証プロセスをセキュリティを犠牲にしてではなく、それらのサービスに実装するためにできるだけ簡単にしたいです。このようなシナリオの標準およびベストプラクティスは何ですか?

私が考えることができる(または私に提案された)オプション:

  1. クライアントサービスに「偽の」ユーザー名とパスワードを持たせ、ユーザーと同じ方法で認証します。私はこのオプションが好きではありません-それはちょうどいい感じではありません。

  2. クライアントサービスの永続的なアプリケーションID、場合によってはアプリケーションキーも割り当てます。私が理解している限り、これはユーザー名とパスワードを持っているのと同じです。このIDとキーを使用して、各リクエストを認証するか、認証トークンを作成してさらにリクエストを認証できます。いずれにしても、アプリケーションIDとキーを取得できる人はだれでもクライアントになりすますことができるため、このオプションは好きではありません。

  3. 前のオプションにIPアドレスチェックを追加できます。これにより、偽のリクエストを実行することが難しくなります。

  4. クライアント証明書。独自の認証局を設定し、ルート証明書を作成し、クライアントサービス用のクライアント証明書を作成します。ただし、a)証明書なしでユーザーに認証を許可する方法、およびb)クライアントサービスの観点からこのシナリオを実装するのはどのくらい複雑ですか?

  5. 他に何か-他にも解決策があるはずですか?

私のサービスはJavaで実行されますが、基本的な原則に興味があり、実装の詳細にはあまり興味がないため、どの特定のフレームワークに基づいて構築するかに関する情報を意図的に省略しました-このための最良のソリューションを想定しています基盤となるフレームワークに関係なく実装できます。しかし、私はこの主題に少し慣れていないので、実際の実装に関する具体的なヒントと例(有用なサードパーティライブラリ、記事など)も同様に高く評価されます。

113
Tommi

この問題の解決策は、共有秘密に要約されます。ハードコードされたユーザー名とパスワードのオプションも好きではありませんが、非常にシンプルであるという利点があります。クライアント証明書も優れていますが、本当に違いますか?サーバーとクライアントに証明書があります。主な利点は、ブルートフォースが難しいことです。うまくいけば、それに対して保護するために、他の保護が用意されています。

クライアント証明書ソリューションのポイントAを解決するのは難しいとは思いません。ブランチを使用するだけです。 if (client side certificat) { check it } else { http basic auth }私はJavaエキスパートではないので、クライアント側の証明書を作成するためにこれまで働いたことはありません。しかし、簡単なGoogleが このチュートリアル を導き、あなたの路地を見上げます。

このような「最善」の議論にもかかわらず、「コードが少ないほど、賢さが少ないほど良い」という別の哲学があることを指摘したいだけです。 (私は個人的にこの哲学を保持しています)。クライアント証明書ソリューションは、多くのコードのように聞こえます。

OAuthに関する質問を表明したことは承知していますが、OAuth2の提案には、「 bearer tokens 」と呼ばれる問題の解決策が含まれており、SSLと組み合わせて使用​​する必要があります。簡単にするために、ハードコードされたユーザー/パス(アプリごとに1つ)を選択するか、非常によく似たベアラートークンを選択すると思います。

33
newz2000

あなたの質問を読んだ後、私は言う、要求を行うために特別なトークンを生成します。このトークンは、特定の時間(1日で言うことができます)に存在します。

以下は、認証トークンを生成するための例です。

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)

例:2011年6月3日

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630

次に、「my4wesomeP4ssword!」のようにユーザーパスワードと連結します

11630my4wesomeP4ssword!

次に、その文字列のMD5を実行します。

05a9d022d621b64096160683f3afe804

リクエストを呼び出すときは、常にこのトークンを使用してください。

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata

このトークンは毎日一意であるため、この種の保護は、常にサービスを保護するのに十分すぎると思います。

希望は助けます

:)

35
kororo

あなたが取ることができるいくつかの異なるアプローチがあります。

  1. RESTfulの純粋主義者は、BASIC認証を使用し、すべてのリクエストで資格情報を送信することを望みます。その理由は、誰も状態を保存していないということです。

  2. クライアントサービスは、セッションIDを保持するCookieを保存できます。私は個人的に、私が耳にする純粋主義者の何人かほど不快ではないと思います。何度も何度も認証するのは高価です。ただし、このアイデアはあまり好きではないようです。

  3. あなたの説明から、あなたが興味を持っているように思えます OAuth2 私のこれまでの経験から、私の経験では、それは一種の混乱であり、一種の出血するエッジです。実装はありますが、それらはほとんどありません。 Javaでは、Spring3の security モジュールに統合されていることを理解しています。 (それらは tutorial とうまく書かれています。) Restlet に拡張機能があるかどうかを確認するのを待っていましたが、今のところ提案されていますが、インキュベーターでは、まだ完全には組み込まれていません。

11
jwismar

5。他に何か-他の解決策があるはずですか?

あなたは正しい、あります!そして、それはJWT(JSON Web Tokens)と呼ばれます。

JSON Web Token(JWT)は、JSONオブジェクトとして当事者間で情報を安全に送信するためのコンパクトで自己完結型の方法を定義するオープンスタンダード(RFC 7519)です。この情報はデジタル署名されているため、検証および信頼できます。 JWTは、秘密(HMACアルゴリズムを使用)またはRSAを使用する公開/秘密キーペアを使用して署名できます。

JWTを調べることを強くお勧めします。これらは、代替ソリューションと比較した場合の問題に対するはるかに単純なソリューションです。

https://jwt.io/introduction/

3
justin.hughey

クライアント証明書のアプローチに関する限り、クライアント証明書を使用せずにユーザーを許可しながら、実装するのはそれほど難しくありません。

実際に独自の自己署名認証局を作成し、各クライアントサービスにクライアント証明書を発行した場合、それらのサービスを簡単に認証できます。

使用しているWebサーバーに応じて、クライアント証明書を受け入れるが、必要としないクライアント認証を指定する方法が必要です。たとえば、Tomcatでは、httpsコネクタを指定するときに、「true」または「false」の代わりに「clientAuth = want」を設定できます。次に、自己署名CA証明書をトラストストアに追加します(Webサーバー構成で別のファイルを指定しない限り、デフォルトで使用しているJREのcacertsファイル)。したがって、信頼できる証明書は、自己署名CA。

サーバー側では、要求からクライアント証明書を取得できる場合(null以外)に保護するサービスへのアクセスのみを許可し、追加のセキュリティが必要な場合はDNチェックに合格します。クライアント証明書を持たないユーザーの場合、ユーザーは引き続きサービスにアクセスできますが、リクエストには証明書が存在しません。

私の意見では、これが最も「安全な」方法ですが、学習曲線とオーバーヘッドがあることは確かであるため、必ずしもニーズに最適なソリューションとは限りません。

3
bobz32

私はアプローチを信じています:

  1. 最初のリクエスト、クライアントはID /パスコードを送信します
  2. 一意のトークンのID /パスを交換
  3. 有効期限が切れるまで、後続の各リクエストでトークンを検証します

実装方法やその他の特定の技術的詳細に関係なく、かなり標準的です。

本当にエンベロープをプッシュしたい場合は、資格情報が検証されるまでクライアントのhttpsキーを一時的に無効な状態と見なし、資格情報が有効でない場合は情報を制限し、有効期限が切れたときに有効になったらアクセスを許可できます。

お役に立てれば

3
Dynrepsys

サーバーでセッションを作成し、REST呼び出しごとにクライアントとサーバー間でsessionIdを共有できます。

  1. 最初にRESTリクエストを認証します:/authenticatesessionId: ABCDXXXXXXXXXXXXXX;で応答を返します(クライアントの形式に従って)。

  2. このsessionIdを実際のセッションとともにMapに保存します。 Map.put(sessionid, session)またはSessionListenerを使用して、キーを作成および破棄します。

    public void sessionCreated(HttpSessionEvent arg0) {
      // add session to a static Map 
    }
    
    public void sessionDestroyed(HttpSessionEvent arg0) {
      // Remove session from static map
    }
    
  3. URL?jsessionid=ABCDXXXXXXXXXXXXXX(または他の方法)のようなREST呼び出しごとにsessionidを取得します。

  4. HttpSessionを使用してマップからsessionIdを取得します。
  5. セッションがアクティブな場合、そのセッションのリクエストを検証します。
  6. 応答またはエラーメッセージを送り返します。
1
arviarya

ユーザーがリクエストを承認すると、他のアプリが認証に使用する一意のトークンを生成すると、アプリケーションIDパラメーターを使用してユーザーをサイトにリダイレクトするアプリケーションを使用します。このようにして、他のアプリケーションはユーザー資格情報を処理せず、他のアプリケーションをユーザーが追加、削除、管理できます。 Foursquareおよび他のいくつかのサイトはこの方法を認証し、他のアプリケーションとして非常に簡単に実装できます。

0
Devin M