WEBサイト上のメール認証(アクティベーション)手法を考える
ユーザー登録機能を持ったWEBサイトを構築する際にメールアドレスを登録してもらう手順で、安全な仕組みを考える必要があったので、あらためて考えてみました。
ここで解説する認証方法では、メールアドレスだけでなく、同時にパスワード等の入力情報も含めて認証することができる方法を紹介していますので、ユーザー認証方法に悩んでいる方は参考にしてみてください。
仕組み自体は王道パターンで
手順は以下のように王道とも言えるものになっています。
- メールアドレスをユーザーに入力してもらう。
- 入力されたメールアドレス先に認証(アクティベーション)メールを送信。
- ユーザーは認証メール内のURLにアクセス。
- WEBシステム側でURLに含まれる認証コードを確認。
- 1で入力されたメールアドレスをデータベースに登録。
これをアクティビティ図で表すと以下のようになります。
さて、ここでポイントとなるのは認証コードの作成と認証コードの確認方法です。
まず認証コードの作成。
良く行われるのが、メールアドレス等のユーザー独自の入力ソースを元にハッシュ関数等を使って暗号化された認証コードを作成する方法。 例えばPHPでsha256を使って認証コードを作成する例は以下のようなものです。
ハッシュ関数にはメールアドレス+システム側で用意した任意の秘密文字列(一般に「Salt」と言います)を加えて暗号化(ハッシュ化)し、予測できないようにします。
define('ACTIVATE_SALT', '9XHSYE892KANDH8291'); function createActivationCode($email) { return hash_hmac('sha256', $email, ACTIVATE_SALT); }
ここでもう1つの問題。 認証コードの確認方法をどうするか?
やりたい事は、発行した認証コードをユーザーから受け取って
「受け取った認証コード=さっき入力されたメールアドレス」
というように紐付けすることです。
認証コードとメールアドレスの紐付け方法を考える
1.認証用URLにメールアドレスも載せると…
手っ取り早いのは、認証メールに記載するURLに「認証コード」に加えて「メールアドレス」も併記する方法でしょう。 例えば以下のような認証メールを発行してみます。
以下のURLをクリックして登録を完了させてください。 https://www.example.com/signup/activate/?act=...&mail=yamashita@colo-ri.jp
しかし、URLにメールアドレスが記載されるとURLが長くなってしまうし、何より気持ちが悪い、セキュリティ的に大丈夫か、などと不審がるユーザーもいます。
2.メールを再入力させると…
では、認証コードのみを特定のWEBページに入力させる仕様だとどうでしょうか?
残念ながら、この方法は認証コードと紐付けるメールアドレスも併せて入力してもらわないといけません。 まぁ、なんて不恰好なフォームでしょう。
認証コード | |
---|---|
メールアドレス | |
3.メールアドレスをセッションに保存すると…
メールアドレスをブラウザのセッションに保存しておき、認証時に取得して利用するという手もありますが、この方法にもいくつか欠点があります。
session_start(); $_SESSION['activate_mail'] = $mail;
セッションの有効期限が切れると無効になってしまう点や、別のPCやスマートフォンのブラウザでアクセスされてしまうとセッション自体が存在しないため、メールアドレスとの紐付けができなくなってしまうのです。
そこでどうするか? ここからが本番。
入力情報を格納した認証ファイルを作成して解決
上記の認証問題を一気に解決するのが、認証ファイルアクティベーションです。
この方法は以下の手順により、認証コードのみで入力情報との紐付けを可能にします。
- メールアドレスをユーザーに入力してもらう。
- 認証コードを作成。
- サーバーに「(認証コード).activate」等の一時認証ファイルを作成。
- 認証ファイル内に入力情報を書き込み。
- ユーザーに認証メールを送信
- ユーザーは認証メール内のURLにアクセス。
- WEBシステム側でURLに含まれる認証コードを確認。
- 3で作成されたファイルを読み込み、メールアドレスを取り出し。
- データベースに登録。
- 認証ファイルを削除。
認証ファイルアクティベーションのメリット
認証ファイルアクティベーションのメリットは、システム外部に対して「認証コードのみを見せる」というセキュリティ性、匿名性の高さにあります。
もちろん、認証ファイルは外部からアクセスできない領域に保存しておく必要があります。
また、認証コードを入力できるページを設けることで、認証コードさえあれば場所を問わず、どこででも認証することができます。
これは、メール以外の通知方法でも認証コードを発行することができるということです。
さらに、認証ファイル自体はテキストファイルなので、最初の入力時にメールアドレスだけでなく、パスワードや住所情報などの個人情報もまとめて保存し、認証時に読み出すことができるので、汎用性の高い認証システムを作ることができます。
例えば、ユーザーによるメールアドレス変更機能を実装する場合は、認証ファイルにユーザーIDを保存しておけば、認証する際にユーザーIDを使ってユーザー情報を取り出すことができます。
認証ファイルは「/tmp」ディレクトリ内に作成するか、cron等で定期的にクリアして、ゴミデータが溜まらないようにしておきましょう。
データベースに保存する手もあり
認証コードと入力情報をデータベースに保存しておき、認証コード確認時にクリアするという手もあります。
tmpuserテーブル
tmpuser_id | tmpuser_activatecode | tmpuser_email |
---|---|---|
1 | a9bc78… | yamashita@colo-ri.jp |
ただ、この方法ですと正規に登録するかどうかも分からないデータに対してデータベースというコストのかかる処理を実装することになるので、定期的なメンテナンス方法も含めて採用を検討したほうが良いでしょう。
大手企業サイトやユーザー登録型のサイトでは恐らくデータベース内に認証コードを保存する方法で認証ロジックが作られているのではないかと思います。
…というわけで
いかがだったでしょうか?
認証部分に悩んでいるデベロッパーさんに参考にしていただきつつ、より良い認証方法があればぜひ教えていただきたいなと思います。
それでは~。
2012-07-02