認証とセッション管理のためのSPAのベストプラクティス


308

Angular、Ember、Reactなどのフレームワークを使用してSPAスタイルのアプリケーションを構築する場合、認証とセッション管理のベストプラクティスは何だと思いますか?問題への取り組みを検討する方法はいくつか考えられます。

  1. APIとUIのオリジンドメインが同じであると想定して、通常のWebアプリケーションでの認証と同じように扱います。

    これには、セッションCookie、サーバー側セッションストレージ、およびおそらく認証済みWeb UIがヒットして現在のユーザー情報を取得し、パーソナライゼーションやクライアント側の役割/機能の決定に役立つ可能性があるいくつかのセッションAPIエンドポイントが含まれる可能性があります。もちろん、サーバーは引き続きデータへのアクセスを保護するルールを適用し、UIはこの情報を使用してエクスペリエンスをカスタマイズします。

  2. パブリックAPIを使用するサードパーティのクライアントと同様に扱い、OAuthと同様のトークンシステムで認証します。このトークンメカニズムは、サーバーAPIに対して行われたすべてのリクエストを認証するためにクライアントUIによって使用されます。

私はあまり専門家ではありませんが、ほとんどの場合、#1で完全に十分ですが、経験豊富な意見をいくつか聞きたいです。


私はこのようにしています、stackoverflow.com
a / 19820685/454252

回答:


477

この質問は、少し異なる形で詳細にここで扱われました:

RESTful認証

しかし、これはサーバー側から対処します。これをクライアント側から見てみましょう。ただし、その前に、重要な前奏曲があります。

Javascript暗号は絶望的

これに関するマタサノの記事は有名ですが、そこに含まれる教訓は非常に重要です。

https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/

要約する:

  • 中間者攻撃では、暗号コードを簡単に置き換えることができます <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
  • 中間者攻撃は、非SSL接続を介してリソースを提供するページに対して簡単です。
  • SSLを取得したら、とにかく実際の暗号を使用します。

そして、私の独自の結果を追加するには:

  • XSS攻撃が成功すると、SSLを使用している場合でも、攻撃者がクライアントのブラウザでコードを実行する可能性があります。そのため、すべてのハッチが攻撃されても、攻撃者が実行方法を見つけた場合、ブラウザの暗号は失敗する可能性があります。他の誰かのブラウザ上のjavascriptコード。

これにより、JavaScriptクライアントを使用する場合、RESTful認証スキームの多くが不可能または愚かになります。見てみよう!

HTTP基本認証

何よりもまず、HTTP Basic Auth。最も簡単なスキーム:すべてのリクエストで名前とパスワードを渡すだけです。

もちろん、これには絶対にSSLが必要です。すべてのリクエストでBase64(可逆)エンコードされた名前とパスワードを渡すためです。回線を聞いている人はだれでも簡単にユーザー名とパスワードを抽出できます。「Basic Auth is insecure」の引数のほとんどは、ひどい考えである「Basic Auth over HTTP」の場所から来ています。

ブラウザーは組み込みのHTTP Basic Authサポートを提供しますが、それは罪として醜いので、アプリではおそらく使用しないでください。ただし、JavaScriptでユーザー名とパスワードを隠しておく方法もあります。

これは最もRESTfulなソリューションです。サーバーは、状態に関する知識を一切必要とせず、ユーザーとの個々の対話をすべて認証します。一部のREST愛好家(ほとんどが麦わら)は、あらゆる種類の状態を維持することは異端であり、他の認証方法を考えれば口の中で泡立つと主張します。この種の標準準拠には理論上の利点があります。Apacheがそのままサポートします。必要に応じて、オブジェクトを.htaccessファイルで保護されたフォルダにファイルとして保存できます。

問題は?クライアント側でユーザー名とパスワードをキャッシュしています。これにより、evil.ruに優れた亀裂が生じます。最も基本的なXSS脆弱性でさえ、クライアントがユーザー名とパスワードを悪意のあるサーバーに送信する可能性があります。パスワードをハッシュ化してソルト処理することで、このリスクを軽減することもできますが、JavaScript Cryptoは絶望的です。このリスクは、ブラウザの基本認証サポートに任せることで軽減できますが、前述のように醜い罪です。

HTTPダイジェスト認証

jQueryでダイジェスト認証は可能ですか?

より「安全な」認証、これは要求/応答ハッシュチャレンジです。除きJavaScriptの暗号絶望的であることが唯一のSSL上で動作し、あなたはまだ、クライアント側のユーザー名とパスワードをキャッシュし、それはより多くのHTTP基本認証よりも複雑な作りが、する必要がないので、これ以上確保します

追加の署名パラメーターを使用したクエリ認証。

もう1つの「安全な」認証では、ナンスとタイミングデータでパラメーターを暗号化し(繰り返し攻撃とタイミング攻撃から保護するため)、送信します。これの最も良い例の1つは、OAuth 1.0プロトコルです。これは、私の知る限り、RESTサーバーに認証を実装するためのかなり重要な方法です。

http://tools.ietf.org/html/rfc5849

ああ、でもJavaScript用のOAuth 1.0クライアントはありません。どうして?

JavaScript Cryptoは絶望的です。JavaScriptはSSLなしではOAuth 1.0に参加できず、クライアントのユーザー名とパスワードをローカルに保存する必要があります。これにより、ダイジェスト認証と同じカテゴリに分類されます。HTTP基本認証よりも複雑ですが、安全性は高くありません

トークン

ユーザーはユーザー名とパスワードを送信し、その代わりにリクエストの認証に使用できるトークンを取得します。

ユーザー名とパスワードのトランザクションが完了するとすぐに機密データを破棄できるため、これはHTTP基本認証よりもわずかに安全です。トークンは「状態」を構成し、サーバーの実装をより複雑にするため、RESTfulでもありません。

まだSSL

ただし、トークンを取得するには、最初のユーザー名とパスワードを送信する必要があります。機密情報は依然として、危険なJavaScriptに触れています。

ユーザーの資格情報を保護するには、攻撃者をJavaScriptに近づけないようにする必要があり、ユーザー名とパスワードをネットワーク経由で送信する必要があります。SSLが必要です。

トークンの有効期限

「このトークンが長すぎる場合は破棄して、ユーザーを再度認証させる」などのトークンポリシーを適用するのが一般的です。または「このトークンの使用が許可されている唯一のIPアドレスは確かですXXX.XXX.XXX.XXX」これらのポリシーの多くはかなり良いアイデアです。

消防

ただし、SSLなしでトークンを使用すると、「サイドジャッキング」と呼ばれる攻撃に対して依然として脆弱です:http ://codebutler.github.io/firesheep/

攻撃者はユーザーの資格情報を取得しませんが、それでもユーザーのふりをすることができ、これはかなり悪い場合があります。

tl; dr:暗号化されていないトークンをネットワーク経由で送信することは、攻撃者がそれらのトークンを簡単に取得し、ユーザーのふりをすることができることを意味します。FireSheepは、これを非常に簡単にするプログラムです。

独立した、より安全なゾーン

実行しているアプリケーションが大きくなるほど、機密データの処理方法を変更するコードを挿入できないようにすることが難しくなります。CDNを完全に信頼していますか?あなたの広告主?あなた自身のコードベース?

クレジットカードの詳細では一般的で、ユーザー名とパスワードではあまり一般的ではありません-一部の実装者は、アプリケーションの残りの部分とは別のページに、「機密データの入力」を保持します。ユーザーをフィッシングするのは困難です。

Cookie(単にトークンを意味する)

認証トークンをCookieに入れることは可能です(そして一般的です)。これにより、トークンを使用したauthのプロパティが変更されることはなく、より便利になります。以前のすべての引数が引き続き適用されます。

セッション(まだトークンを意味します)

セッション認証は単なるトークン認証ですが、わずかに異なるもののように見えるいくつかの違いがあります。

  • ユーザーは、認証されていないトークンから開始します。
  • バックエンドは、ユーザーのトークンに関連付けられた「状態」オブジェクトを維持します。
  • トークンはCookieで提供されます。
  • アプリケーション環境は、詳細を抽象化します。

それを除けば、実際にはトークン認証と何の違いもありません。

これは、RESTful実装からさらにさまよっています。ステートオブジェクトを使用すると、ステートフルサーバー上のプレーンオールRPCのパスにさらに進んでいきます。

OAuth 2.0

OAuth 2.0は、「ソフトウェアAがソフトウェアBにユーザーXのログイン認証情報へのアクセス権を与えずに、ソフトウェアBにユーザーXのデータへのアクセス権をどのように付与するか」の問題を調べます。

実装は、ユーザーがトークンを取得し、サードパーティサービスが「はい、このユーザーとこのトークンは一致し、ユーザーからデータの一部を今すぐ取得できる」ための標準的な方法にすぎません。

ただし、基本的に、OAuth 2.0は単なるトークンプロトコルです。他のトークンプロトコルと同じプロパティを示します。これらのトークンを保護するにはSSLが必要です。これらのトークンの生成方法が変更されるだけです。

OAuth 2.0が役立つ2つの方法があります。

  • 他人への認証/情報の提供
  • 他人からの認証/情報の取得

しかし、それには、トークンを使用しているだけです。

あなたの質問に戻る

それで、あなたが尋ねている質問は「私のトークンをクッキーに保存し、私の環境の自動セッション管理に詳細を処理させるべきですか、それとも自分のトークンをJavaScriptに保存して自分でそれらの詳細を処理するべきですか?」ということです。

そして答えは、あなたを幸せにするものなら何でもしなさい

ただし、自動セッション管理の問題は、舞台裏で多くの魔法が起こっていることです。多くの場合、これらの詳細を自分で制御する方が良いです。

私は21歳なので、SSLはイエスです

もう1つの答えは、すべてにhttpsを使用することです。そうしないと、ブリガンドがユーザーのパスワードとトークンを盗みます。


3
すばらしい答えです。トークン認証システムと基本的なCookie認証(Webフレームワークに組み込まれていることが多い)の同等性に感謝します。それは私が探していたものです。検討すべき多くの潜在的な問題を取り上げていただきありがとうございます。乾杯!
Chris Nicola

11
久しぶりですが、これをJWTを含めるように拡張する必要があるのでしょうか。auth0.com/blog/2014/01/07/…–
Chris Nicola、

14
トークン It's also less RESTful, as tokens constitute "state and make the server implementation more complicated."(1)RESTでは、サーバーがステートレスである必要がありますクライアント側に格納されたトークンは、サーバーにとって意味のある方法で状態を表しません。(2)やや複雑なサーバー側コードはRESTfulnessとは関係ありません。
スープドッグ

10
lol_nope_send_it_to_me_insteadこの機能の名前が
Leo

6
あなたが見落としているように見える1つのこと:Cookieは、httpOnlyとマークされている場合はXSSセーフであり、安全で同じサイトでさらにロックダウンできます。そして、クッキーの取り扱いはずっと長くなりました===より多くの戦いが強化されました。トークンのセキュリティを処理するためにJSとローカルストレージに依存するのはばかげています。
Martijn Pieters

57

JWT (JSON Web Tokens)とSSL / HTTPS を使用して、認証プロセスのセキュリティを強化できます。

基本認証/セッションIDは次の方法で盗まれる可能性があります。

  • MITM攻撃(Man-In-The-Middle)-SSL / HTTPSなし
  • 侵入者がユーザーのコンピューターにアクセスする
  • XSS

JWTを使用することで、ユーザーの認証の詳細を暗号化してクライアントに保存し、それをすべてのリクエストとともにAPIに送信します。サーバー/ APIはトークンを検証します。これは、秘密鍵(サーバー/ API店舗密かに)せずに読み込む/復号化することができない 読む更新

新しい(より安全な)フローは次のとおりです。

ログインする

  • ユーザーがログインし、ログイン認証情報をAPIに送信する(SSL / HTTPS経由)
  • APIがログイン資格情報を受け取る
  • 有効な場合:
    • データベースに新しいセッションを登録する
    • JWTのユーザーID、セッションID、IPアドレス、タイムスタンプなどを秘密鍵で暗号化します。
  • APIはJWTトークンをクライアントに送り返します(SSL / HTTPS経由)
  • クライアントはJWTトークンを受け取り、localStorage / cookieに保存します

APIへのすべてのリクエスト

  • ユーザーは、HTTPヘッダーに保存されたJWTトークンを使用して、HTTPリクエストを(SSL / HTTPS経由で) APIに送信します
  • APIはHTTPヘッダーを読み取り、その秘密鍵でJWTトークンを復号化します
  • APIはJWTトークンを検証し、HTTPリクエストのIPアドレスをJWTトークンのIPアドレスと照合し、セッションが期限切れかどうかを確認します
  • 有効な場合:
    • 要求されたコンテンツで応答を返す
  • 無効な場合:
    • 例外をスローする(403/401)
    • システムへの侵入のフラグ
    • ユーザーに警告メールを送信します。

更新された30.07.15:

JWTペイロード/クレームは実際には秘密鍵(シークレット)なしで読み取ることができ、それをlocalStorageに保存することは安全ではありません。私はこれらの誤った発言について申し訳ありません。ただし、JWE標準(JSON Web Encryption)に取り組んでいるようです。

これを実装するには、クレーム(userID、exp)をJWTに保存し、API /バックエンドが知っている秘密鍵(秘密)で署名し、クライアントの安全なHttpOnly Cookieとして保存します。この方法では、XSS経由で読み取ることも操作することもできません。そうでない場合、JWTは署名の検証に失敗します。また、安全なHttpOnly Cookie を使用することで、CookieがHTTPリクエスト経由でのみ送信され(スクリプトからアクセスできません)、安全な接続(HTTPS)経由でのみ送信されることを確認できます。

更新された17.07.16:

JWTは本質的にステートレスです。つまり、無効化/期限切れになります。トークンのクレームにSessionIDを追加することで、トークンをステートフルにします。その有効性は、署名の検証と有効期限だけに依存しないため、サーバー上のセッションの状態にも依存します。ただし、利点は、ステートレスJWTではこれまで不可能だったトークン/セッションを簡単に無効化できることです。


1
結局のところ、JWTは、セキュリティーの観点からはまだ「単なるトークン」です。サーバーは依然としてユーザーID、IPアドレス、タイムスタンプなどを不透明なセッショントークンに関連付けることができ、JWTほど安全ではありません。ただし、JWTのステートレスな性質により、実装が容易になります。
ジェームズ

1
@James JWTには、検証可能であり、重要な詳細を伝達できるという利点があります。これは、クロスドメイン認証が必要な場合など、さまざまなAPIシナリオでかなり役立ちます。セッションが良くないもの。また、実装に役立つ定義済み(または少なくとも進行中)の仕様でもあります。これは、他の優れたトークン実装よりも優れているとは言えませんが、明確に定義されていて便利です。
Chris Nicola

1
@クリスはいあなたのすべての点に同意します。ただし、上記の回答で説明されているフローは、JWTを使用しているため、本来、より安全なフローではありません。さらに、識別子をJWTに関連付けて状態をサーバーに保存しない限り、JWTは上記のスキームでは取り消しできません。それ以外の場合は、ユーザー名/パスワードを要求して定期的に新しいJWTを取得するか(ユーザーエクスペリエンスが悪い)、有効期限が非常に長いJWTを発行する必要があります(トークンが盗まれた場合は悪い)。
James

1
私の答えは100%正解ではありません。JWTは実際には秘密鍵(シークレット)なしで復号化/読み取りでき、それをlocalStorageに保存するのは安全ではないためです。これを実装するには、クレーム(userID、exp)をJWTに保存し、API /バックエンドが知っている秘密鍵(秘密)で署名し、クライアントにHttpOnly Cookieとして保存します。そうすれば、XSSで読み取ることができません。ただし、トークンがMITM攻撃で盗まれる可能性があるため、HTTPSを使用する必要があります。私はこれを反映するために私の答えを更新します。
ガウイ2015

1
@vsenko Cookieは、クライアントからの要求ごとに送信されます。JSからCookieにアクセスするのではなく、クライアントからAPIへの各HTTPリクエストに関連付けられています。
ガウイ

7

2つ目はトークンシステムです。

ember-authまたはember-simple-authについてご存知ですか?どちらもember-simple-auth状態のようなトークンベースのシステムを使用します。

Ember.jsアプリケーションでトークンベースの認証を実装するための軽量で目立たないライブラリ。 http://ember-simple-auth.simplabs.com

セッション管理があり、既存のプロジェクトに簡単にプラグインできます。

Ember-simple-authのEmber App Kitサンプルバージョンもあります。OAuth2認証にember-simple-authを使用したember-app-kitの実際の例です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.