1. ホーム
  2. security

[解決済み] 認証とセッション管理に関するSPAのベストプラクティス

2022-03-15 12:49:36

質問事項

Angular、Ember、React などのフレームワークを使用して SPA スタイルのアプリケーションを構築する場合、認証とセッション管理のベストプラクティスは何だと思われますか。私は、この問題にアプローチすることを考えるいくつかの方法を考えることができます。

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

    これはおそらく、セッションクッキー、サーバーサイドのセッションストレージ、そして認証されたウェブUIが現在のユーザー情報を取得し、パーソナライズや、おそらくクライアントサイドでの役割/能力の決定に役立つセッションAPIエンドポイントを持っていることを含むでしょう。もちろん、サーバーはデータへのアクセスを保護するルールを適用し、UIはこの情報を使ってエクスペリエンスをカスタマイズするだけです。

  2. パブリックAPIを使用する他のサードパーティークライアントと同様に扱い、OAuthに似たある種のトークンシステムで認証する。このトークンシステムは、クライアントUIがサーバーAPIへの各リクエストを認証するために使用されます。

私はあまり専門家ではありませんが、ほとんどの場合、#1で十分だと思います。

どのように解決するのですか?

この質問については、少し形を変えて、こちらで長く取り上げています。

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脆弱性でさえ、クライアントが自分のユーザ名とパスワードをevilサーバーに送信する結果になりえます。パスワードをハッシュ化したり塩漬けにしたりして、このリスクを軽減しようとすることはできますが、覚えておいてください。 JavaScriptの暗号化には絶望的 . ブラウザのBasic Authサポートに任せることで、このリスクを軽減することもできますが、...前述したように、醜いものです。

HTTPダイジェスト認証

jQueryでDigest認証は可能ですか?

より安全な認証で、リクエスト/レスポンス型のハッシュ・チャレンジです。ただし JavaScriptの暗号は絶望的 また、ユーザー名とパスワードをクライアント側でキャッシュする必要があるため、HTTP Basic Auth よりも複雑です。 これ以上安全ではない .

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

パラメータをnonceとタイミングデータで暗号化し(リピート攻撃やタイミング攻撃から守るため)、送信する、よりquot;secure"なauthもあります。この最良の例の一つがOAuth 1.0プロトコルで、私の知る限りでは、RESTサーバに認証を実装するための非常に優れた方法です。

https://www.rfc-editor.org/rfc/rfc5849

あ、でもJavaScript用のOAuth 1.0クライアントはないんですよね。なぜですか?

JavaScriptの暗号は絶望的 を覚えておいてください。JavaScript は SSL なしでは OAuth 1.0 に参加できませんし、クライアントのユーザー名とパスワードをローカルに保存する必要があります。 これ以上安全ではない .

トークン

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

これはHTTP Basic Authよりもわずかに安全です。なぜなら、ユーザー名とパスワードのトランザクションが完了すると同時に、機密データを破棄することができるからです。また、トークンは「ステート」と呼ばれ、サーバーの実装が複雑になるため、RESTfulではありません。

SSLはまだか

しかし、トークンを取得するために最初のユーザー名とパスワードを送信しなければならないのは難点です。機密情報はまだあなたの妥協可能なJavaScriptに触れています。

ユーザーの認証情報を保護するためには、攻撃者がJavaScriptにアクセスできないようにする必要があり、ユーザー名とパスワードを無線で送信する必要があることに変わりはないのです。SSLが必要です。

トークンの有効期限

トークンの使用期間が長すぎる場合、トークンを破棄し、再度認証を行う必要があります。 XXX.XXX.XXX.XXX となります。これらのポリシーの多くは、かなり良いアイデアです。

ファイヤーシーピング

しかし、SSLを使わずにトークンを使用すると、「サイドジャック」と呼ばれる攻撃に対して脆弱なままです。 http://codebutler.github.io/firesheep/

攻撃者はあなたのユーザーの認証情報を取得しませんが、あなたのユーザーのふりをすることができ、これはかなりまずいことになります。

tl;dr: 暗号化されていないトークンを無線で送るということは、攻撃者が簡単にそのトークンを盗み出し、あなたのユーザーのふりをすることができるということです。FireSheepは、これを非常に簡単に行うことができるプログラムです。

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

実行中のアプリケーションが大規模になればなるほど、機密データの処理方法を変更するようなコードを注入されないことを絶対に保証することは難しくなります。CDNを絶対的に信頼していますか?広告主は?あなた自身のコードベースは?

いくつかの実装者は、「機密データ入力」をアプリケーションの他の部分とは別のページ、厳しく管理され、可能な限りロックダウンできるページ、できればユーザをフィッシングするのが難しいページに保持します。

クッキー(トークンという意味です)

認証トークンをクッキーに入れることは可能(かつ一般的)です。これはトークンを使ったauthの特性を変えるものではなく、どちらかというと利便性のためのものです。これまでの議論はすべてそのまま適用されます。

セッション(やはりトークンの意味しかない)

Session AuthはToken認証に過ぎないが、若干の違いがあるように思われる。

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

それ以外は、Token Authと何ら変わりはないのですが。

これは、RESTfulな実装からさらに迷走しています。ステート・オブジェクトを使用すると、ステートフルなサーバー上の単なる古いRPCの道をますます突き進むことになります。

OAuth 2.0

OAuth 2.0は、「ソフトウェアAは、ソフトウェアBがユーザーXのログイン認証情報にアクセスすることなく、どのようにしてユーザーXのデータにアクセスできるようにするか」という問題に着目しています。

この実装は、ユーザーがトークンを取得し、サードパーティのサービスが「このユーザーとこのトークンは一致しました。

しかし、基本的には、OAuth 2.0は単なるトークンプロトコルです。トークンを保護するためにSSLが必要であることは変わりませんが、トークンの生成方法が変わっただけなのです。

OAuth 2.0は、2つの方法で役に立ちます。

  • 他者への認証・情報提供
  • 他者から認証・情報を取得する

でも、結局のところ、あなたは...トークンを使っているだけなのです。

質問に戻る

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

そして、その答えは あなたが幸せになれることなら何でもしてください .

しかし、セッションの自動管理については、あなたのために舞台裏で多くのマジックが起こっているということです。多くの場合、これらの詳細を自分でコントロールする方が良いのです。

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

もう1つの答えは さもなければ、山賊がユーザーのパスワードとトークンを盗みます。