パスワードポリシー
パスワードの長さ / 複雑さ / 保存方法を定める方針。NIST SP 800-63B-4 が示す現行の要件と、旧来の常識との違いを整理する
パスワードポリシーとは
パスワードポリシーは、ユーザーが設定するパスワードの要件 (長さ、複雑さ) と管理ルール (保存方法、有効期限) を定義するセキュリティ方針である。要件の国際的な基準は NIST SP 800-63B が示しており、現行版は 2025 年 7 月公開の Revision 4 (SP 800-63B-4) である。2017 年に出て 2020 年 3 月に正誤が反映された Revision 3 は、この版に置き換えられた。要件は「必須」と「推奨」で強度が書き分けられているため、どちらで書かれた項目かを読み分けないと、過剰な実装にも不足した実装にもなる。
NIST の推奨 (従来の常識を覆す)
Revision 4 の要点は、文字種の強制と定期変更という 2 つの旧来の常識を明確に否定したことである。この 2 項目は Revision 3 では「そうすべきでない」という推奨だったが、Revision 4 で「してはならない」という必須要件へ格上げされた。最小文字数も一律ではなく、そのパスワード単独で認証するのか、多要素認証の一要素として使うのかで要求値が変わる。
| 項目 | 旧来の常識 | SP 800-63B-4 の要件 |
|---|---|---|
| 最小文字数 | 8 文字 | 単独で認証に使うパスワードは 15 文字以上が必須。多要素認証の一要素としてのみ使う場合に限り 8 文字以上でよい |
| 最大文字数 | 上限を短く切る | 64 文字以上を受け付けることが推奨。送られたパスワードは全文を検証し、切り詰めてはならない |
| 複雑さの要件 | 大文字+小文字+数字+記号を強制 | 文字種の混在などの構成規則を課してはならない |
| 定期変更 | 90 日ごとに変更 | 定期的な変更を要求してはならない。侵害の証拠があるときは変更を強制する |
| 秘密の質問 | 使用 | パスワードを選ばせる場面で秘密の質問や知識ベース認証を促してはならない |
| パスワードヒント | 使用 | 未認証の相手から読めるヒントを保存させてはならない |
| 漏洩リストとの照合 | 任意 | 設定時と変更時に、既知の漏洩・頻出パスワードのリストと全文で照合することが必須。該当したら理由を示して選び直させる |
| 試行回数の制限 | 任意 | 認証失敗の回数を実効的に制限する仕組みが必須 |
| パスワード管理ツール | 貼り付けを禁止 | 利用を許可することが必須。自動入力が使えない場面に備えて貼り付けも認めることが推奨 |
複雑さの強制は、ユーザーが P@ssw0rd! のような予測可能なパターンを使う原因になる。長いパスフレーズの方が桁数を稼ぎやすく、覚える負担も小さい。
ただし例として広まったフレーズをそのまま使うことはできない。correct horse battery staple を Pwned Passwords の漏洩データに照合すると、空白を含む綴り・空白を詰めた綴り・語頭を大文字にした綴りのいずれも登録済みで、2026 年 8 月時点で数百から数千件の出現が返る。上の表にある漏洩リスト照合を実装していれば弾かれる側の文字列であり、パスフレーズは利用者が自分で語を無作為に選んで組み立てる必要がある。
パスワードの保存
保存側の要件は、ソルトを付けてパスワードハッシュ方式に通すこと、ソルトを 32 ビット以上にすること、コスト係数を運用に支障が出ない範囲でできるだけ高くし、計算機の性能向上に合わせて引き上げていくことである。
次の設定は Argon2id を RFC 9106 が 2 番目に推奨する構成、すなわち反復 3 回・並列度 4・メモリ 64 MiB に合わせたものである。2 GiB のメモリを認証処理に割ける環境なら、同 RFC が 1 番目に推奨する反復 1 回・メモリ 2 GiB を選べる。
import { hash, verify } from '@node-rs/argon2';
// ✅ Argon2id でハッシュ化して保存
const passwordHash = await hash(password, {
memoryCost: 65536, // 64MB
timeCost: 3,
parallelism: 4,
});
// 検証
const isValid = await verify(passwordHash, inputPassword);
| アルゴリズム | 推奨度 | 特徴 |
|---|---|---|
| Argon2id | 最推奨 | メモリハード、GPU 攻撃に強い |
| bcrypt | 推奨 | 広くサポート、72 バイト制限 |
| scrypt | 推奨 | メモリハード |
| SHA-256 + salt | 非推奨 | 高速すぎてブルートフォースに弱い |
| MD5 / SHA-1 | 禁止 | 脆弱性あり |
この推奨度は実務で広く共有されている評価であり、NIST が承認した方式の一覧とは別物である。SP 800-63B-4 は方式の具体名を挙げず SP 800-132 の最新版に委ねており、名前を挙げていた Revision 3 でも例示は PBKDF2 と Balloon で、Argon2 は含まれていない。FIPS 準拠が要求される案件では、Argon2id を選ぶ前に承認済み方式の範囲を確認する。
bcrypt の 72 バイト制限は、長いパスワードが無駄になるだけでは済まない。超過分は黙って捨てられるため、全文を切り詰めずに検証するという要件と衝突する。1 文字 3 バイトになる日本語を含むパスフレーズなら 24 文字前後で上限に達し、それ以降の入力の違いは検証に効かなくなる。
漏洩パスワードのチェック
漏洩リストとの照合は必須要件であり、自前でリストを抱えない場合は Have I Been Pwned の Pwned Passwords API を使う。ユーザーが設定しようとしているパスワードが過去の漏洩データに含まれていないかを、設定時と変更時に確認する。
import { createHash } from 'crypto';
async function isPasswordBreached(password: string): Promise<boolean> {
const sha1 = createHash('sha1').update(password).digest('hex').toUpperCase();
const prefix = sha1.slice(0, 5);
const suffix = sha1.slice(5);
const res = await fetch(`https://api.pwnedpasswords.com/range/${prefix}`, {
headers: { 'Add-Padding': 'true' },
});
const text = await res.text();
return text.split('\n').some((line) => {
const [hashSuffix, count] = line.trim().split(':');
return hashSuffix === suffix && Number(count) > 0;
});
}
k-Anonymity モデルにより、パスワード全体を API に送信しない。送るのは SHA-1 の先頭 5 文字だけで、応答は「残りの 35 文字:出現回数」という行が並んだ本文である。
照合を text.includes(suffix) のような部分一致で書くと 2 つの理由で誤判定する。1 つは出現回数を読まずに行の存在だけを見てしまうこと、もう 1 つは Add-Padding ヘッダーを付けたときに混ぜられる詰め物の行を拾ってしまうことである。詰め物は応答の件数を無作為に水増しし、応答の大きさから検索した接頭辞を推測されるのを防ぐ仕組みで、公式ドキュメントでは 800 件から 1,000 件の範囲に揃えると説明されている。詰め物の行は出現回数が 0 になっているため、行単位に分けて、残り 35 文字の完全一致と出現回数が 1 以上であることの両方を確かめる。
パスワードポリシーの理解を深めるには関連書籍が参考になる。
この記事は役に立ちましたか?
関連用語
関連する記事
Web 開発本ガイド - フロントエンドからバックエンドまで
Web 開発の全体像を学べる技術書の選び方と学習マップを紹介。フレームワーク本の賞味期限問題と公式ドキュメントとの使い分けも解説します。
ゼロから作る Deep Learning シリーズの読む順番 - 全 6 巻の内容と選び方を整理
ゼロから作る Deep Learning シリーズ全 6 巻 (基礎 / 自然言語処理 / フレームワーク / 強化学習 / 生成モデル / LLM) の読む順番を解説。各巻の内容 / 発売年 / 前提知識を一覧表で整理し、目的別にどの巻から読むべきかを案内します。
技術書の読書メモ術 - 読んだ内容を確実に定着させる記録法
技術書の内容を定着させる 3 行メモ法と、ツール選び、メモを実務に活かす仕組みを紹介します。