web-dev-qa-db-ja.com

トークンをcookie、localstorage、またはセッションに保存する必要がありますか?

申し訳ありませんが、これはおそらく他の多くの人が尋ねた質問ですが、一部の参照には多くの異なる方法があるため、私は本当に混乱しています。

React SPA、Express、Expressセッション、Passport、JWTを使用したIam

したがって、Cookie、セッション、およびJWT /パスポートについて混乱しています。

多くのWebサイトはCookieを使用してショッピングカートトークンを格納しています。これまでのところ、Cookieを追加せずに、セッションIDに基づいてショッピングカートデータを保存しています。

したがって、ユーザーが私のウェブサイトにアクセスすると、それをreq.sessionIDと照合し、ショッピングカートやユーザーセッションなどのデータベース内のデータを取得します。

私の質問はcookieを保存する必要があるのですか?req.sessionIDを介してアクセスして必要なデータを取得できるためです。

そして2番目

passport-google-oauth20を使用して認証を行いました。ログインに成功すると、データがセッションに保存されます。クライアントに送信するには、URLクエリ?token='sdsaxas'を使用して送信する必要があります。

この場合、私は多くの意見の相違を得ます。誰かがそれをローカルストレージに保存し、誰かがJWTを使用してトークンに変換することでCookieに保存しました。

 jwt.sign(
        payload,
        keys.jwt.secretOrPrivateKey, 
        {
            expiresIn:keys.jwt.expiresIn // < i dont know what is this expired for cookies or localstorage ?
        }, (err, token) => {

            res.redirect(keys.Origin.url + "?token=" + token);
        });

結論はすべてがセッションに関連しているので、セッションIDを使用してすべてを実行できるということですか?Cookieまたはlocalstorageなしで

React SPAを使用しているため、1回またはすべてのページ更新でフェッチを実行し、データを取得してからreduxに保存することによってのみ

25
Faris Dewantoro

この回答はステートレスなアプローチに基づいているため、従来のセッション管理については触れていません

完全に異なる2つの質問をしました。

  1. ショッピングカート-ビジネス機能との関連性が高い
  2. OAuth 2&JWT-セキュリティと認証に関連しています

EコマースWebサイトのユーザーとして、職場に通勤しているときにモバイルデバイスからショッピングカートに追加したアイテムは、自宅に到着した後、PCからWebサイトにログインしたときにカートで利用できるはずです。したがって、カートデータはバックエンドDBに保存され、ユーザーアカウントにリンクされる必要があります。

OAuth 2.0を使用した認証の場合、JWTアクセストークンまたは更新トークン、あるいはその両方をクライアントデバイスのどこかに保存する必要があるため、ユーザーがログイン認証情報を提供して自分自身を認証した後は、 Webサイトをナビゲートするには、資格情報を再度提供する必要があります。このコンテキストでは、ブラウザのローカルストレージ、セッションストレージ、Cookieがすべて有効なオプションです。ただし、ここではCookieはサーバー側のどのセッションにもリンクされていないことに注意してください。つまり、CookieにはセッションIDが格納されません。 Cookieは単にアクセストークンのストレージとして使用されるだけで、httpリクエストごとにサーバーに渡され、サーバーはデジタル署名を使用してトークンを検証し、改ざんされていないこと、および有効期限が切れていないことを確認します。

アクセストークンまたは更新トークン、あるいはその両方の3つのストレージオプションはすべて一般的ですが、Cookieは正しい方法で使用する場合に最も安全なオプションのようです。

これをよりよく理解するために、OAuth 2.0仕様とともに this および this を読むことをお勧めします。

2019年2月16日更新

先ほど言ったように、Cookieが最も安全なオプションのようです。ここでポイントをさらに明確にしたいと思います。

ブラウザlocalStoragesessionStorageが認証トークンを格納するための十分なセキュリティを提供しないと思う理由は次のとおりです。

  1. XSSが発生すると、悪意のあるスクリプトはそこからトークンを簡単に読み取り、リモートサーバーに送信できます。その後、リモートサーバーまたは攻撃者は、被害者のユーザーになりすましても問題はありません。

  2. localStoragesessionStorageはサブドメイン間で共有されません。したがって、異なるサブドメインで2つのSPAを実行している場合、1つのアプリで保存されたトークンを組織内の他のアプリで使用できないため、SSO機能は利用できません。 iframeを使用するいくつかの解決策がありますが、それらは良い解決策というよりは回避策のように見えます。また、応答ヘッダーX-Frame-Optionsを使用してiframeによるクリックジャッキング攻撃を回避する場合、iframeを使用した解決策は問題外です。

ただし、これらのリスクは、フィンガープリント( OWASP JWTチートシート で説明)を使用することで軽減できます。

フィンガープリントの考え方は、暗号化された強力なバイトのランダム文字列を生成することです。生の文字列のBase64文字列は、HttpOnlySecureSameSite Cookieに名前のプレフィックス__Secure-を付けて保存されます。ドメインおよびパス属性の適切な値は、ビジネス要件に従って使用する必要があります。文字列のSHA256ハッシュもJWTのクレームで渡されます。したがって、XSS攻撃が攻撃者が制御するリモートサーバーにJWTアクセストークンを送信しても、元の文字列をCookieで送信できないため、サーバーはCookieがないことに基づいて要求を拒否できます。 HttpOnlyであるCookieは、XSSスクリプトで読み取ることができません。

したがって、localStorageおよびsessionStorageを使用する場合でも、Cookieを使用して保護する必要があります。その上で、前述のようにサブドメイン制限を追加します。

現在、Cookieを使用してJWTを格納することに関する唯一の懸念は、CSRF攻撃です。 SameSite Cookieを使用しているため、クロスサイトリクエスト(AJAXまたはハイパーリンク経由のみ)ができないため、CSRFは軽減されます。サイトがSameSite Cookieをサポートしていない古いブラウザや他のあまり人気のないブラウザで使用されている場合でも、すべてのAJAXリクエストはCookie値を読み取り、Cookie値をカスタムHTTPヘッダーに追加します(GETおよびHEADリクエストは状態の変更を想定していない)。同じOriginポリシーのためにCSRFは何も読み取ることができず、POST、PUT、DELETEなどの安全でないHTTPメソッドの利用に基づいているため、このCSRF Coo​​kieはCSRFリスクを軽減します。 CSRF Coo​​kieを使用するこのアプローチは、すべての最新のSPAフレームワークで使用されています。 Angularアプローチについて言及します here

また、CookieはhttpOnlyおよびSecuredであるため、XSSスクリプトはそれを読み取ることができません。したがって、XSSも軽減されます。

XSSとスクリプトインジェクションは、適切なcontent-security-policy応答ヘッダーを使用することでさらに軽減できることにも言及する価値があるかもしれません。

その他のCSRF緩和アプローチ

  1. 状態変数(Auth0が使用)-クライアントはすべてのリクエストで暗号的に強力なランダムナンスを生成して渡します。サーバーはそのレスポンスとともにエコーバックし、ナンスを検証できるようにします。 Auth0 doc で説明されています。
  2. 常にリファラーヘッダーを確認し、リファラーが信頼できるドメインである場合にのみリクエストを受け入れます。リファラーヘッダーがないか、ホワイトリストに登録されていないドメインの場合は、リクエストを拒否してください。 SSL/TLSリファラーを使用する場合、通常は存在します。ランディングページ(ほとんどが情報提供であり、ログインフォームやセキュリティで保護されたコンテンツを含まない)は少し緩和され、リファラーヘッダーのないリクエストを許可する可能性があります
  3. TRACE HTTPメソッドはhttpOnly Cookieの読み取りに使用できるため、サーバーでブロックする必要があります
  4. また、ヘッダーStrict-Transport-Security:max-age =;を設定します。 includeSubDomainsは、セキュリティで保護された接続のみを許可し、中間者がサブドメインからのCSRF Coo​​kieを上書きしないようにします
31
Saptarshi Basu

HTTPはステートレスプロトコルです。 詳細についてはその回答をお読みください。ただし、基本的には、WebサーバーなどのHTTPサーバーは、1つの要求の存続期間を超えてクライアントに関する情報を保存しないことを意味します。これは、どのユーザーがログインしているかを思い出せないことを意味するため、Webアプリの問題です。

これに対する解決策としてCookieが発明されました。 Cookieは、クライアントとサーバーがeveryリクエストごとに送受信するテキストデータです。クライアントとサーバーが通信するたびに覚えていることについて合意することで、アプリケーションの状態データを効果的に維持できます。

つまり、基本的に、Cookieなしではセッションを確立できません。セッションIDを少なくとも格納するCookieが必須であるため、現在ログインしているユーザーを確認できますセッションを検索してアプリ。これは、エクスプレスセッションの機能です。 ドキュメント メインsessionメソッドの場合、セッションIDがCookieに保存されていることを明示的に示します。

私の質問はcookieを保存する必要があるのですか?req.sessionIDを介してアクセスして必要なデータを取得できるためです。

あなたはクッキーを保存する必要はありません。 express-sessionがこれを行います。アプリケーション全体はCookieを保存する必要があります。それがなければ、req.sessionID 見上げる。

0
Effective Robot