web-dev-qa-db-ja.com

RESTホイールを再発明せずにAPIを保護する

REST APIを設計するとき、最初にユーザーを認証するのは一般的ですか?

私が探している典型的なユースケースは次のとおりです。

  • ユーザーがデータを取得したい。確かに私たちは共有したいと思います!公開APIキーを取得して、すぐに読んでください!
  • ユーザーがデータの保存/更新を希望しています...待ってください!あなたは誰ですか、これができますか?

私は一度それを構築し、Webアプリ、AndroidアプリケーションまたはiPhoneアプリケーションがそれを使用することを許可することを許可したいと思います。

REST APIは、このような要件を持つ論理的な選択のようです

私の質問を説明するために、簡単な例を使用します。

データベースにアイテムがあり、rating属性(整数1〜5)があります。

RESTを正しく理解すれば、csv、xml、またはjsonを次のように返す選択した言語を使用してGETリクエストを実装できます。

http://example.com/product/getrating/{id}/

返すJSONを選択するとします。

{
  "id": "1",
  "name": "widget1",
  "attributes": { "rating": {"type":"int", "value":4} }
}

これは、公開APIに適しています。その部分を取得します。

たくさんの質問があるのは、これをセキュリティモデルとどのように組み合わせるかです。私は常にユーザーを識別するセッション状態を持つWebアプリのセキュリティに慣れているため、ユーザーが送信することにしたかどうかに関係なく、ユーザーができることを制御できます。私はそれを理解しているように、これはRESTfulではないので、この場合には悪い解決策になります。

同じアイテム/評価を使用して別の例を使用してみます。

ユーザー「JOE」がratingitemに追加する場合

これは次を使用して実行できます。

http://example.com/product/addrating/{id}/{givenRating}/

この時点で、「JOE」が製品{id}に{givenRating}の評価を与えたというデータを保存します。

質問:リクエストが「BOB」ではなく「JOE」から送信されたことを知るにはどうすればよいですか。

さらに、ユーザーの電話番号などのより賢明なデータ用の場合はどうでしょうか?

私がこれまでに得たのは:

1)HTTPの組み込み機能を使用して、プレーンHTTPまたはHTTPSのいずれかの要求ごとに認証します。

これは、すべてのリクエストが次の形式になることを意味します。

https://joe:[email protected]/product/addrating/{id}/{givenRating}/

2)秘密鍵と公開鍵を使用したAmazon S3のようなアプローチを使用します。 http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3)とにかくCookieを使用し、RESTのステートレス部分を破壊します。

2番目のアプローチは私には良いように見えますが、本当にこの全体を再発明する必要があるのか​​疑問に思っています。ハッシュ、保存、キーの生成などをすべて自分で行いますか?

これは、典型的なWebアプリケーションでセッションを使用し、スタック全体を自分で書き直すのとよく似ています。通常、特にセキュリティを扱う場合は「間違っている」という意味です。

編集:私はOAuthも同様に言及すべきだったと思います。

73
jfrobishow

5年後に編集

OAuth2を使用してください!

以前のバージョン

いいえ、Cookieを使用する必要はまったくありません。 HTTP Digest、OAuthまたはAmazonのAWS(コピーするのは難しくありません)ほど安全ではありません。

Cookieを確認する方法は、Basic/Digest/OAuth /のいずれかと同じくらいの認証トークンですが、あまり適切ではないということです。

ただし、Cookieの使用がRESTful原則自体に反するとは感じません。ただし、セッションCookieの内容がサーバーから返すリソース。

クッキーは悪です。使用をやめてください。

21
Evert

「RESTful」であること、セキュリティを心配する必要はありません。以下にその方法を示します。

手順1:ユーザーが資格情報を使用して認証サービスにアクセスします。

ステップ2:資格情報をチェックアウトし、フィンガープリント、セッションIDなどを返し、後ですばやく取得できるように共有メモリにポップするか、Webサービスの所要時間に数ミリ秒を追加することを気にしない場合はデータベースを使用します。

ステップ3:エントリポイントコールを、everyWebサービスリクエストのフィンガープリントとセッションIDを検証するすべてのWebサービススクリプトの先頭に追加します。

ステップ4:指紋とセッションIDが有効でない場合、または認証へのリダイレクトがタイムアウトした場合。

これを読む:

RESTful認証

21
Daniel Pereira

3年後編集

私はEvertに完全に同意し、HTTPSで OAuth2 を使用し、車輪を再発明しないでください! :-)

単純なREST APIによって-サードパーティクライアント向けではありません- JSON Web Tokens も同様に有効です。

以前のバージョン

とにかくCookieを使用して、RESTのステートレス部分を破壊します。

セッションを使用しないでください。RESTサービスは十分にスケーラブルではありません...ここには、アプリケーション状態(またはクライアント状態またはセッション)とリソース状態の2つの状態があります。アプリケーションの状態にはセッションデータが含まれ、RESTクライアントによって維持されます。リソース状態にはリソースのプロパティと関係が含まれ、RESTサービスによって維持されます。特定の変数がアプリケーション状態またはリソース状態の一部であるかどうかを非常に簡単に決定できます。アクティブなセッションの数とともにデータ量が増加する場合、そのデータはアプリケーション状態に属します。したがって、たとえば、現在のセッションによるユーザーIDはアプリケーション状態に属しますが、ユーザーのリストまたはユーザー権限はリソース状態に属します。

したがって、RESTクライアントは識別要素を保存し、要求ごとに送信する必要があります。 RESTクライアントとHTTPクライアントを混同しないでください。それらは同じではありません。 RESTクライアントは、curlを使用する場合はサーバー側にも存在できます。たとえば、CORSを介してRESTサービスと共有できるサーバー側httpのみのCookieを作成できます。重要なのは、RESTサービスがすべてのリクエストで認証する必要があるため、すべてのリクエストで資格情報(ユーザー名、パスワード)を送信する必要があることです。

  • クライアント側のRESTクライアントを記述する場合、SSL + HTTP認証を使用してこれを行うことができます。その場合、サーバー上でcredentials -> (identity, permissions)キャッシュを作成して、認証を高速化できます。キャッシュをクリアし、ユーザーが同じリクエストを送信すると、同じレスポンスが返されることに注意してください。少し時間がかかります。これをセッションと比較できます。セッションストアをクリアすると、ユーザーはstatus: 401 unauthorized応答を受け取ります...
  • サーバー側のRESTクライアントを作成し、curlを介してRESTサービスに識別要素を送信する場合、2つの選択肢があります。 http認証も使用できます。または、RESTクライアントではなくRESTサービスではセッションマネージャーを使用できます。
  • 信頼されていないユーザーがRESTクライアントを書き込んだ場合、ユーザーを認証し、異なるクライアントにアクセス許可を付与するかどうかを決定する可用性を提供するアプリケーションを作成する必要があります。 Oauthはそのための既存のソリューションです。 Oauth1の方が安全であり、oauth2の方が安全ではありませんが、より簡単です。この問題には他にもいくつかの解決策があると思います...これを再発明する必要はありません。 oauthを使用した完全な認証および承認ソリューションがあります。たとえば、 wso identity server です。

クッキーは必ずしも悪いわけではありません。クライアント状態を保持し、サービスがリソース状態のみを保持するまで、RESTfulな方法で使用できます。たとえば、カートまたは優先ページ付け設定をCookieに保存できます...

8
inf3rno