Web サービスにパスワードは必要ない

Your users don’t need a password

translated on

Web サイトを開発する際のアーキテクチャ設計において、ユーザーの認証にはメールとパスワードを利用するのが一般的でしょう。この設計は身に染み付いていて、なぜユーザーにパスワードを作成させるのか、考えもしないかもしれません。私たちは慣れてしまったのです。

しかし、ユーザーはパスワードを必要としない可能性があります。

一つの解決策は OAuth 2.0 ですが、すべてのユーザーがSNSのアカウントを持っているわけでもなく、あなたのサイトでそのアカウントを使用したいと考えているとも限りません。

では、あなたはどのようにしてパスワードを使わずユーザーを認証しますか?その回答はこの記事を読めばわかります。

何が問題か?

最も安全なパスワードは、あなたが覚えられないパスワードです

Troy Hunt

そもそもパスワードそれ自体に問題があります。あなたや、あなたのユーザーにとっても良いものではありません。

極端に言えば、パスワードは、サイトのオーナーにとってシステムの脆弱性です。ハッシュアルゴリズムがどれほど強力でも、遅かれ早かれ、GPU も CPU も進化するので、いずれ無意味になるでしょう。万が一データベースに侵入された場合、あなたとあなたのユーザーにとっても大きな打撃をうけるでしょう。

ユーザーにとって、パスワードの入力は鬱陶しいものです。リテラシーの低いユーザーは、いつも使ってるパスワードを使い、パスワードを失うリスクが高くなります。リテラシーが高いユーザーは、そのサイト固有のパスワードを使うか、パスワードマネージャを利用するでしょう。

パスワードマネージャはすでにダーティーハックであり、パスワードの無能さと非効率性に気づくべきです。

さらに、定期的にパスワードを変更することをを強要したり、特殊文字を含めることを必須にすることで、ユーザーの生活を不便なものにすることになるでしょう。

どうするべきか?

答えは、パスワードを利用しないことです。メールのみを使います。

まず、ユーザーがサイトに登録した時点で、既にメールアドレスに依存しています。確認リンク付きのメールを送信したり、ユーザーのパスワードをリセットする際にメールを使うと思います。

「パスワードのリセット」はすでに矛盾しているようにみえます。メールのリンクをクリックするだけでパスワードを変更できるのです。変ですよね?それなのになぜ、ユーザーにパスワードを作ることを強要し、さらにはあなたのお気に入りの特殊文字を含めることを強要させるのでしょう?

ユーザーを認証するときは、登録確認メールを送るときと同様に、リンクを含むメールを送信するだけです。ユーザーを認証するにはこれで十分です。

モダンなメールサービスは、一般的な Web サイトよりもセキュリティが強固で、ハッカーの攻撃に備えられています。パスワードの保管はプロに委ねましょう。

解決策

例として、PostgreSQL を用いたシンプルなサイトのデータベース構造を見てみましょう。

まずは2つのテーブルを作ります:

users テーブル

Column name Data type Attributes
id serial PRIMARY KEY
email varchar(320) UNIQUE

sign_in_requests テーブル

Column name Data type Attributes
id serial PRIMARY KEY
email varchar(320)
token uuid UNIQUE
request_ip varchar(45)
activated_at timestamp NULLABLE
expired_at timestamp

補足情報:

  • sign_in_requests テーブルは、"Sign Up" テーブルと同じであるべきです。なぜなら、このシステムにおいては、役割が同等であるためです。
  • 上記の点に基づき、sign_in_requests テーブルの email カラムは、重複するため外部キーにしていません。
  • token の型は uuid である必要はありません。手動で入力しやすくするために短くすることもできます。しかし、そうした場合、トークンの衝突やセキュリティリスクは悪化します。
  • request_ip は任意です。アクセス制限をしたい等がある場合に使用してください。

アルゴリズム:

  1. ユーザーはメールを入力しログインを要求
  2. sign_in_request を作成し、https://example.com/signin/callback/email/{{token}} のようなトークン付きリンクをメールでユーザーに送信
  3. ユーザーはメールのリンクをクリックし、トークンを用いてデータベースにリクエスト
  4. ユーザーから送信されたトークンが存在し、期限が有効で、トークンが他に使用されていなく、メールが一致する場合、ログインを許可
  5. トークンを複数回使用されるのを防ぐために、activated_at = now() のようにする
  6. 最後に、パスワードを持つシステムと同じように、ユーザーにクッキーや JWT などを付与

スパム防止のために、10分毎に1回しかメールを送信しないなど、制限を行ってください。

誰のため?

この手法を使うべきは以下のようなケースです:

  • ブログ、ニュース、フォーラムのような大半の Web サイト
  • ユーザーのメールアドレスを既に使用しているサイト
  • 定期的に利用されるが、頻繁には利用されないようなサービス(例えば ISP の課金システム等)

しかし、以下のケースではこの手法を使わないでください:

  • あなたがメールサービスを提供している場合(Gmail 等)
  • あなたの主なユーザーが、モバイルアプリケーション、スマートTV、IoT の場合。この場合、パスワードを利用したほうが簡単です。

結果

一見するとパスワードを捨てるという考え方はクレージーに見えますが、それは多くのメリットをもたらし、あなたとあなたのユーザーの生活を楽にするでしょう。