Angular、Ember、Reactなどのフレームワークを使用してSPAスタイルのアプリケーションを構築するとき、人々は認証およびセッション管理のためのベストプラクティスであると思いますか?問題への取り組みを検討する方法はいくつか考えられます。
APIとUIに同じOriginドメインがあると仮定して、通常のWebアプリケーションでの認証と同じように扱います。
これにはおそらくセッションCookie、サーバー側のセッションストレージ、そしておそらく認証されたWeb UIがパーソナライズやクライアント側のロール/能力の決定に役立つように現在のユーザー情報を取得するためにヒットできるセッションAPIエンドポイントがあります。サーバーはもちろんデータへのアクセスを保護するルールを強制します。UIはこの情報を使用してエクスペリエンスをカスタマイズします。
パブリックAPIを使用している他のサードパーティ製クライアントと同様に扱い、OAuthと同様の何らかのトークンシステムで認証します。このトークンメカニズムは、クライアントAPIがサーバーAPIに対して行われたすべての要求を認証するために使用されます。
私はここではあまり専門家ではありませんが、#1で大部分のケースで完全に十分であるように思えます、しかし私は本当にいくつかのより経験豊富な意見を聞きたいです。
この質問は、やや異なる形式で、長々とここで対処されています。
ただし、これはサーバー側から対処します。これをクライアント側から見てみましょう。ただし、その前に、重要なプレリュードがあります。
これに関するMatasanoの記事は有名ですが、そこに含まれるレッスンは非常に重要です。
http://www.matasano.com/articles/javascript-cryptography/
要約する:
<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
で簡単に置き換えることができますそして、独自の結果を追加するには:
これにより、JavaScriptクライアントを使用する場合、多くのRESTful認証スキームが不可能または愚かになります。見てみよう!
何よりもまず、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はHopelessです。ブラウザの基本認証サポートに任せることでこのリスクを軽減することができますが、前述のように、罪としてはasいです。
より「安全な」認証、これはリクエスト/レスポンスハッシュチャレンジです。 JavaScript CryptoはHopelessを除き、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でもありません。
ただし、トークンを取得するには、その初期ユーザー名とパスワードを送信する必要があります。機密情報は、侵害される可能性のあるJavaScriptに影響を与えます。
ユーザーの資格情報を保護するには、攻撃者がJavaScriptにアクセスできないようにする必要があり、ユーザー名とパスワードをネットワーク経由で送信する必要があります。 SSLが必要です。
「ねえ、このトークンが長すぎた場合は破棄して、ユーザーを再度認証させる」などのトークンポリシーを適用するのが一般的です。または「このトークンの使用が許可されている唯一のIPアドレスはXXX.XXX.XXX.XXX
であると確信しています。」これらのポリシーの多くは、非常に優れたアイデアです。
ただし、SSLなしでトークンを使用すると、「サイドジャッキング」と呼ばれる攻撃に対して依然として脆弱です。 http://codebutler.github.io/firesheep/
攻撃者はユーザーの資格情報を取得しませんが、ユーザーのふりをすることはできますが、これはかなり悪い場合があります。
tl; dr:暗号化されていないトークンをネットワーク経由で送信することは、攻撃者がそれらのトークンを簡単に奪い、ユーザーのふりをすることができることを意味します。 FireSheepは、これを非常に簡単にするプログラムです。
実行しているアプリケーションが大きいほど、機密データの処理方法を変更するコードをインジェクトできないようにすることは絶対に難しくなります。 CDNを絶対に信頼していますか?広告主ですか?あなた自身のコードベース?
クレジットカードの詳細には一般的であり、ユーザー名とパスワードにはあまり一般的ではありません-一部の実装者は、「機密データ入力」をアプリケーションの残りの部分とは別のページ、厳しく制御および可能な限り最適にロックダウンできるページに保持しますユーザーをフィッシングするのは困難です。
認証トークンをCookieに入れることは可能です(そして一般的です)。これは、トークンを使用したauthのプロパティを変更するものではなく、より便利なものです。前述の引数はすべて適用されます。
セッション認証は単なるトークン認証ですが、若干の違いがあるため、若干異なるもののように見えます。
ただし、それを除けば、実際にはトークン認証と違いはありません。
これは、RESTful実装からさらに遠ざかります。ステートオブジェクトを使用すると、ステートフルサーバー上のプレーンol 'RPCのパスをさらに進んでいきます。
OAuth 2.0は、「ソフトウェアBがユーザーXのログイン資格情報にアクセスすることなく、ソフトウェアAがソフトウェアXにユーザーXのデータにアクセスする方法」の問題を調べます。
この実装は、ユーザーがトークンを取得し、サードパーティのサービスが「はい、このユーザーとこのトークンが一致し、データを今すぐ取得できます」という標準的な方法です。
ただし、基本的に、OAuth 2.0は単なるトークンプロトコルです。他のトークンプロトコルと同じプロパティを示します-それらのトークンを保護するにはSSLが必要です-トークンの生成方法を変更するだけです。
OAuth 2.0が役立つ2つの方法があります。
しかし、最終的には、トークンを使用するだけです。
したがって、あなたが尋ねている質問は、「トークンをCookieに保存し、環境の自動セッション管理で詳細を処理する必要がありますか、それともJavascriptにトークンを保存し、それらの詳細を自分で処理する必要がありますか?」
そして答えは:あなたを幸せにするものは何でもしてください。
ただし、自動セッション管理に関することは、舞台裏で多くの魔法が発生するということです。多くの場合、これらの詳細を自分で管理する方が適切です。
もう1つの答えは、すべてにhttpsを使用するか、ブリガンドがユーザーのパスワードとトークンを盗むことです。
JWT(JSON Web Tokens)とSSL/HTTPSを使用することで認証プロセスのセキュリティを強化できます。
基本認証/セッションIDは、次の方法で盗まれる可能性があります。
JWTを使用することで、ユーザーの認証情報を暗号化してクライアントに格納し、それをAPIへのすべての要求とともに送信します。サーバー/ APIはトークンを検証します。 秘密鍵(サーバー/ APIが秘密に保管する)がないと、復号化/読み取りできません。 更新を読みます。
新しい(より安全な)フローは次のようになります。
更新30.07.15:
JWTのペイロード/クレームは実際には秘密鍵(secret)がなくても読み取ることができ、localStorageに格納するのは安全ではありません。私はこれらの誤った声明についてすみません。しかし彼らは、 JWE標準(JSON Web Encryption) に取り組んでいるようです。
私はJWTにクレーム(userID、exp)を格納し、API /バックエンドが知っているだけの秘密鍵(secret)で署名し、それを安全なHttpOnlyクッキーとしてクライアントに格納することでこれを実装しました。この方法では、XSSを介して読み取ることはできず、操作することもできません。そうしないと、JWTは署名の検証に失敗します。また、セキュアなHttpOnlyCookieを使用することで、CookieがHTTPリクエスト経由でのみ送信され(スクリプトからアクセスできない)、セキュア接続経由(HTTPS)でのみ送信されるようになります。
17.07.16を更新しました。
JWTは本来、ステートレスです。それは彼らが自分自身を無効にするか、または失効させることを意味します。トークンの有効性は署名の検証と有効期限にのみ依存するのではなく、トークンの要求にSessionIDを追加してステートフルにすることで、サーバーのセッション状態にも依存します。ただし、利点はトークン/セッションを簡単に無効にできることです。これまでステートレスJWTでは不可能でした。
私は第二に、トークンシステムに行きます。
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の動作例