1. ホーム
  2. ruby-on-rails

[解決済み] deviseのtoken_authenticatableは安全ですか?

2023-07-29 08:53:11

質問

シンプルなAPIを構築しています。 RailsのAPI で簡単なAPIを作っているのですが、ここで正しい道を歩んでいることを確認したいと思います。私はログインを処理するためにdeviseを使用しており、Deviseの token_authenticatable オプションを使用することにしました。このオプションは、各リクエストで送信する必要のある API キーを生成します。

私はAPIをバックボーン/マリオネットフロントエンドと組み合わせており、一般的にセッションをどのように扱うべきか疑問に思っています。私の最初の考えは、ローカルストレージまたはクッキーに API キーを保存し、ページロード時にそれを取得することでしたが、その方法で API キーを保存することについては、セキュリティの観点から気になることがありました。ローカルストレージやクッキーを見たり、通過したリクエストをスニッフィングすることで、簡単にapiキーを取得し、それを使って無期限にそのユーザーになりすますことができるのではないでしょうか?私は現在、ログインのたびにapiキーをリセットしていますが、それでも頻繁なようです。どのデバイスでログインしても、他のデバイスではログアウトしてしまうことになり、ちょっと面倒です。このリセットがなくなれば、ユーザビリティの面でも改善されるような気がします。

私はここで完全に間違っているかもしれませんが (そうであることを望みます)、この方法で認証することが確実に安全であるかどうか、また、そうでない場合、良い代替案は何か、どなたか説明していただけないでしょうか。全体として、私は、頻繁に再認証を強制することなく、ユーザーが API アクセスに「サインイン」している状態を安全に維持できる方法を探しています。

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

token_authenticatable はタイミング攻撃に対して脆弱です。 このブログ記事 . これらの攻撃は token_authenticatable が Devise 3.1 で削除された理由です。を参照してください。 plataformatec ブログ記事 をご覧ください。

最も安全なトークン認証の仕組みを持つために、トークンを

  1. HTTPS 経由で送信する必要があります。

  2. 暗号強度のあるランダムなものである必要があります。

  3. 安全に比較されなければなりません。

  4. データベースに直接保存してはならない。トークンのハッシュのみ保存可能です。(トークン = パスワードであることを忘れないでください。パスワードを平文でデータベースに保存することはありませんよね)

  5. 何らかのロジックに従って期限切れになるはずです。

使いやすさを優先してこれらの点のいくつかを見送ると、可能な限り安全でないメカニズムになってしまいます。それはとてもシンプルなことです。最初の 3 つの要件を満たし、データベースへのアクセスを制限すれば、十分に安全であるはずです。

私の答えを拡大解釈して説明します。

  1. HTTPSを使用する . これはスニッファーに対処するため、間違いなく最も重要なポイントです。

    HTTPSを使用しない場合、多くのことがうまくいかない可能性があります。たとえば

  2. でトークンを生成します。

    なぜこれが必要なのかの説明については、以下のサイトを読むことをお勧めします。 sysrandom のREADMEとブログの記事 様々なプログラミング言語で安全な乱数を生成する方法 .

  3. ユーザーのIDやメールなどの属性を使って、ユーザーレコードを探します。そして、そのユーザーのトークンとリクエストのトークンを比較し Devise.secure_compare(user.auth_token, params[:auth_token] . Rails 4.2.1+を使用している場合は、次のようにすることもできます。 ActiveSupport::SecurityUtils.secure_compare .

    行う ではなく のようなRailsのファインダでユーザレコードを検索します。 User.find_by(auth_token: params[:auth_token]) . これはタイミング攻撃に弱い!

  4. もし、ユーザーごとに複数のアプリケーション/セッションを同時に使用するのであれば、2つの選択肢があります。

    • 暗号化されていないトークンをデータベースに保存して、デバイス間で共有できるようにする。これは悪い習慣ですが、UX の名において (そして DB アクセスを従業員に任せている場合)、そうすることができるのでしょう。

    • 現在のセッションを許可したい数だけ、ユーザーごとに暗号化されたトークンを保存します。したがって、2 つの異なるデバイスで 2 つのセッションを許可したい場合、2 つの異なるトークン ハッシュをデータベースに保存します。このオプションは、実装が少し簡単ではありませんが、間違いなく安全です。また、トークンを無効にすることで、特定のデバイスで現在進行中のセッションを終了させることができます (たとえば GitHub やFacebookがそうであるように)。

  5. トークンを失効させる何らかのメカニズムが必要です。このメカニズムを実装する際には、UXとセキュリティのトレードオフを考慮してください。

    Googleは6ヶ月間使用されないとトークンを失効させる .

    Facebookは2ヶ月間使用されなかった場合、トークンを失効させます。 :

    FacebookのSDKを使用するネイティブモバイルアプリは、約60日間有効なアクセストークンを取得します。 トークンを取得します。これらのトークンは、アプリを使用する人が Facebook のアプリケーションにリクエストを送信すると、1 日に 1 回更新されます。 このトークンは、アプリを使用する人がFacebookのサーバーにリクエストを送信すると、1日に1回更新されます。 サーバーにリクエストしたときに更新されます。リクエストがない場合、トークンは約60日後に失効します。 トークンは約60日後に失効し、ユーザーは新しいトークンを取得するために再度ログインする必要があります。 新しいトークンを取得する必要があります。

  6. Rails 4にアップグレードして、その暗号化されたCookieストアを使用する。それができない場合は、提案されているように、自分でCookieストアを暗号化します。 はこちら . 暗号化されたクッキーストアに認証トークンを保存することは、全く問題ないでしょう。

また、たとえば、トークンのサブセットまたはデータベース内のすべての単一のトークンをリセットするための rake タスクなど、不測の事態に備えた計画を立てる必要があります。

手始めに、以下のサイトをチェックしてみてください。 この gist (Deviseの著者の一人)で、Deviseでトークン認証を実装する方法を確認してみてください。最後に API のセキュリティに関する Railscast は参考になるはずです。