二要素認証とパスワードセキュリティのベストプラクティス
Webアプリケーションを構築し、ユーザーがサインアップしています。しかし、彼らのアカウントは本当に安全でしょうか?弱いパスワードと二要素認証(2FA)の欠如は、攻撃者が侵入する最も簡単な方法の一つです。このガイドでは、今日から実装できる、実用的で時代を超えたパスワードセキュリティと2FAのベストプラクティスを紹介します。
パスワードセキュリティが依然として重要な理由
長年の警告にもかかわらず、パスワードはほとんどのWebアプリケーションで主要な認証方法であり続けています。攻撃者はこれを知っており、フィッシング、クレデンシャルスタッフィング、ブルートフォースを通じてパスワードを狙います。一つのパスワードが侵害されるだけで、アカウント乗っ取り、データ盗難、評判の損害につながる可能性があります。
強力なパスワードポリシーと2FAは、攻撃者のハードルを大幅に上げます。両方を正しく行う方法を見てみましょう。
パスワードの保存:正しいハッシュ化
パスワードを平文で保存しないでください。常に、パスワード用に設計された強力で遅いアルゴリズムでハッシュ化します。SHA-256のような高速ハッシュは、迅速なブルートフォース攻撃を可能にするため不適切です。
推奨アルゴリズム:
- Argon2id – Password Hashing Competitionの勝者で、GPU攻撃やサイドチャネル攻撃に耐性があります。
- bcrypt – 広くサポートされ、実績があり、設計上遅いです。
- scrypt – メモリハードで、ハードウェア加速攻撃の防止に適しています。
Node.jsでbcryptを使用する例:
const bcrypt = require('bcrypt');
const saltRounds = 12;
async function hashPassword(password) {
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
常にパスワードごとに一意のソルトを使用します(ほとんどのライブラリはこれを自動的に処理します)。ハッシュ化がサーバー上で約100~500msかかるようにコストファクターを調整します。
実際に役立つパスワードポリシー
「記号と数字を含める必要がある」といった複雑なルールは忘れましょう。現代のガイダンス(NIST SP 800-63B)は以下を推奨しています:
- 最小長8文字ですが、パスフレーズ(例:4つ以上のランダムな単語)を奨励します。
- 侵害されたパスワードリスト(例:Have I Been Pwned API)に対してチェックします。
- 侵害が疑われない限り、定期的な有効期限切れを強制しないでください。
- すべての印刷可能なASCII文字とスペースを許可します。
- ブルートフォースを防ぐためにログイン試行をレート制限します。
正当なパスワードをブロックせずにフィードバックを提供する、シンプルな強度メーターを実装します。
二要素認証(2FA)の方法
2FAは第二の要素を追加します:あなたが持っているもの(電話、ハードウェアキー)またはあなた自身(生体認証)。以下は、セキュリティでランク付けされた一般的な方法です:
| 方法 | セキュリティ | 使いやすさ |
|---|---|---|
| ハードウェアセキュリティキー(WebAuthn/FIDO2) | 高 | 中 |
| 認証アプリ(TOTP) | 高 | 高 |
| プッシュ通知 | 中 | 高 |
| SMSコード | 低 | 高 |
SMSはSIMスワッピングや傍受に対して脆弱です。可能な場合はTOTPまたはWebAuthnを優先してください。
TOTPベースの2FAの実装
TOTP(時間ベースのワンタイムパスワード)は、セキュリティと使いやすさのバランスが優れています。以下は高レベルのワークフローです:
- ユーザーの秘密鍵を生成します(例:32ランダムバイト、base32エンコード)。
- otpauth:// URIを作成し、ユーザーが認証アプリでスキャンするためのQRコードを表示します。
- 2FAを有効にする前に、ユーザーが有効なコードを生成できることを確認します。
- 秘密鍵を安全に保存します(保存時に暗号化)。
- アカウント回復用のバックアップコードを提供します。
ログイン時、パスワードを確認した後、TOTPコードを要求します。otplibやspeakeasyのようなライブラリで検証します。
const { authenticator } = require('otplib');
// Generate secret
const secret = authenticator.generateSecret();
// Verify token
const isValid = authenticator.verify({ token: userToken, secret });
クロックドリフトを考慮して、小さな時間枠(例:±1間隔)を許可します。
WebAuthn:認証の未来
WebAuthn(FIDO2の一部)は、ハードウェアキーやプラットフォーム認証器(Touch ID、Windows Hello)を使用したパスワードレスおよび第二要素認証を可能にします。資格情報がオリジンにバインドされているため、フィッシング耐性があります。
WebAuthnの実装には以下が必要です:
- サーバー側のチャレンジ生成と検証。
- WebAuthn APIを使用したクライアント側JavaScript。
- 各ユーザーの公開鍵と資格情報IDの保存。
SimpleWebAuthnのようなライブラリが容易にします。TOTPより複雑ですが、WebAuthnは最強の保護を提供します。
レート制限とアカウントロックアウト
2FAがあっても、パスワードに対するブルートフォース攻撃を防ぐ必要があります。以下を実装します:
- IPごとおよびアカウントごとのレート制限(例:1分あたり5回の試行)。
- 失敗試行後の指数バックオフ。
- 繰り返しの失敗後のアカウントロックアウト、安全なロック解除プロセス(例:メール確認)付き。
- 数回の失敗後のCAPTCHA。
正当なユーザーを永久にロックアウトしないように注意し、一時的なロックアウトを使用してユーザーに通知します。
安全なパスワードリセット
パスワードリセットフローは一般的な攻撃ベクトルです。以下のルールに従います:
- メールで送信される、単一使用、時間制限付きトークンを使用します。
- システムにメールが存在するかどうかを明かさないでください。
- 既にログインしている場合は、ユーザーに再認証を要求します。
- パスワードリセット後にすべてのセッションを無効化します。
ユーザーを責めずに教育する
セキュリティは共同責任です。明確なガイダンスを提供します:
- パスワードマネージャーを使用して、一意のパスワードを生成および保存します。
- 可能な限り2FAを有効にします。
- フィッシング試行に注意します。
アプリ内のヒントと専用のセキュリティページが役立ちます。
FAQ
SMSベースの2FAは2FAなしより良いですか?
はい、SMS 2FAは何もないよりは良いですが、SIMスワッピングや傍受に対して脆弱です。より強力なセキュリティのためにTOTPまたはWebAuthnを優先してください。
パスワードハッシュアルゴリズムをどのくらいの頻度でローテーションすべきですか?
脆弱性が見つからない限り、ローテーションする必要はありません。ただし、パラメータをアップグレードするとき(例:bcryptコストを増やす)に、成功したログインでパスワードを再ハッシュできます。
OAuthやソーシャルログインで2FAを使用できますか?
はい、ただし2FAは通常、IDプロバイダーによって管理されます。ソーシャルログインを使用する場合は、独自のアカウント回復プロセスが安全であることを確認してください。
アプリケーションのセキュリティを強化する準備はできましたか?今日から強力なパスワードハッシュとTOTPベースの2FAを実装することから始めましょう。その他の開発者ツールについては、API応答を迅速にデバッグするためのJSON Formatterをご覧ください。