パスワードポリシー

パスワードの長さ / 複雑さ / 保存方法を定める方針。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 以上であることの両方を確かめる。

パスワードポリシーの理解を深めるには関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事