web-dev-qa-db-ja.com

ユーザーが更新トークンを使用して複数のデバイスから接続できるようにするにはどうすればよいですか?

この質問は私の以前の質問に続きます ユーザーを更新トークンで安全にサインインしたままにするには?

この前の質問で私が得たのは、次のものが必要だということです。

  • 短期間のアクセストークン
  • 長期間ワンタイム更新トークン

更新トークンは、1-1の関係でユーザーと共にDBに保持されます(1ユーザー= 1更新トークン)。ユーザーに対して更新トークンが作成されるたびに、以前のユーザーの永続化トークンがある場合はそれが置き換えられます。これにより、ハッカーは自分の仕事を行うための限られたウィンドウのみを持つことができます。

  • ユーザーがサインインしてアクセストークンA1と更新トークンR1を受け取る
  • ハッカーはそれらのトークンを何らかの方法で取得することを達成します
  • アクセストークンA1が有効期限に達すると、ハッカーは新しいアクセス/リフレッシュトークンを取得しますA2/R2盗まれた更新トークンR1のおかげで:新しく作成された更新トークンR2(ハッカーだけが持っている)は、DB(ユーザーが持っているもの)の以前のR1を置き換えます。
  • 更新トークンR1が存在しないため、ユーザーは新しいアクセストークンの取得に失敗したため、再度サインインして、新しいアクセス/更新トークンA3/R3を取得します:新しく作成された更新トークンR3(ユーザーだけが持っている)は、DB内の以前のR2(ハッカーが持っているもの)を置き換えます
  • ハッカーのアクセストークンA2は期限切れになりますが、更新トークンR2が存在しないため、新しいトークンを取得できません:トークンを再度盗む必要があります(もちろん、難しいと思われます)

ここで私が疑問に思っているのは、ユーザーがこのメカニズムを使用して複数のデバイスから接続できるようにする方法ですか?たとえば、ユーザーが2つの異なるラップトップでサインインした場合、更新トークンは常にお互いを消去します...手がかりはありますか?

8
sp00m

私の意見では、あなたが今質問している質問は、もはやセキュリティに関するものではなく、むしろ概念の実装により焦点を当てています。リフレッシュトークンによって攻撃者にとって困難になることがすでに確立されており、実装が機能しているように見えます。あなたが説明していることから、カスタムソリューションを利用しており、この機能を提供するOAuth2ライブラリ実装のようなものではありません。

ここで決定する必要があるのは、同じユーザーアカウントから複数のデバイス認証が必要かどうかです。ユーザーが1つのアカウントで複数のデバイスからサインインしたくない場合、おめでとうございます。ソリューションは既に機能しています。タイムアウト後に正しいリフレッシュトークンが含まれないため、古いデバイスからすぐにログアウトされます。

ユーザーが同じアカウントの複数のデバイスからサインインできるようにしたい場合は、残念ながらいくつかの変更が必要です。可能な解決策は、データベースにデバイス識別フィールドを追加し、デバイスごとに更新トークンを発行することです。

5
Joe

ジョーの答えに同意する

可能な解決策は、データベースにデバイス識別フィールドを追加し、デバイスごとに更新トークンを発行することです。

しかし、私はいくつかの実装の詳細を追加したいと思います。

IMOの最も堅牢で機能的なソリューションは、各ユーザーがデータベースに多数のレコードを持ち、それぞれに3つの列(access_token、refresh_token、device_id)があることです。

主なケースを調べてみましょう:

  • ユーザーログイン。もちろん、パスワードを使用して作成します。彼はdevice_id(任意の一意の番号、実際には)を渡します。パスワードが正しい場合、サーバーは新しいアクセストークンと更新トークンを生成し、device_idとともにデータベースに挿入します。
  • ユーザーがサービスを使用します。彼はaccess_tokenを送信します(魔女は明らかにユーザーをエンコードする必要があります。たとえば、彼のログインなど)。サーバーは、そのようなログインのために、そのようなaccess_tokenがデータベースに存在するかどうかを確認します。はいの場合-アクセスを許可します。アクセストークンの有効期限が切れた場合、ユーザーは適切なrefresh_tokenおよび(重要!)device_idを使用してトークンを更新できます。データベースのrefresh_tokenがユーザーのトークンと等しくない場合、ハッキングされます。しかし、慌てる必要はありません。このアクセスと更新トークンを削除し、ユーザーをログインページにリダイレクトするだけです。それだけです、ハッカーはもうアクセスできません!
  • ユーザーログアウト。彼はアクセストークンを送信し、データベースはそれを削除し、リストから対応するrefresh_tokenを削除します。 (廃止された未使用のトークンを収集したくない)
  • ユーザーはパスワードを変更します。サーバーは以前のすべてのトークンを削除します。ユーザーが不正アクセスに遭遇すると、パスを変更してすべてのキーを即座に取り消すことができます。 Self-encoded トークンでは、トークンの有効期限が切れるまで待つ必要があるため、これは不可能です。このようなソリューションを使用すると、「すべてのデバイスからのログアウト」機能を実装することも非常に簡単です。
  • ハッカーがaccess_tokenを盗み、ユーザーはそれを知らない。ハッカーは、期限が切れるまで(短い時間枠)のみ使用できます。
  • ハッカーはまた、refresh_tokenを盗み、refreshを作成しました。ユーザーは古いrefresh_tokenを使用できなくなります。その場合、再度ログインするように求められ、新しい更新トークンとアクセストークンが生成され、ハッカーはアクセスを失います。 (ケース#2を参照)

明確に理解しておくべきことの1つは、ハッカーがアクセス/リフレッシュトークンを盗んだ場合にのみ、リフレッシュトークンがあなたを救うことができますが、実際のパスワードは節約できません!彼がパスを取得した場合、問題が発生し、パスワードを復元するためのプロトコルを実装する必要があるためです(たとえば、電子メールやSMSの助けを借りて)。

PS期限切れになる可能性のあるrefresh_tokenを用意することをお勧めします。ケースを防ぐために、ジャッカーが古いデバイスから古いアクセスと参照トークンを失効させた場合、今は決して使用しません。

P.P.S期限切れのrefresh_tokenで行をクリーンアップする定期的なデータベースタスクがあると完璧です(おそらくそのために列refresh_tocken_expiration_dateを追加する必要があります)

P.P.P.S.私はセキュリティの専門家ではないので、より良い解決策があると思われる場合は、ぜひお話しさせていただきます。

読んでくれてありがとう、これが役に立てば幸いです)

2
DmitriyS