安全なパスワードの作り方 — 長さ・文字種・エントロピーの考え方
公開日:
「大文字・小文字・数字・記号を混ぜた8文字以上」といったパスワードのルールはよく見かけますが、それで本当に安全なのかはあまり説明されません。パスワードの強さは、どれだけ推測しにくいかを数値で見積もることができます。この記事では、パスワードが破られる仕組みと、長さと文字種による強さの計算方法、使い回しの危険、そしてパスワードマネージャーを使った現実的な管理方法までを解説します。
パスワードはどうやって破られるのか
安全なパスワードを考える前に、攻撃者がどのようにパスワードを入手・推測するのかを知っておきましょう。主な手口は次のとおりです。
- リスト型攻撃(クレデンシャルスタッフィング): 他のサービスから流出したメールアドレスとパスワードの組み合わせを、別のサービスで試す
- 辞書攻撃: よく使われるパスワードや単語、その変形(P@ssw0rd など)を順に試す
- 総当たり攻撃(ブルートフォース): 考えられる文字の組み合わせをすべて試す
- フィッシング: 本物そっくりの偽サイトに誘導して、利用者自身に入力させる
ログイン画面から直接試す攻撃は、試行回数の制限やアカウントロックで防ぎやすいのに対し、サービスから流出したパスワードのハッシュ値を手元で解析する「オフライン攻撃」では、高性能なGPUを使って1秒間に数十億回以上の推測が行われることもあります。パスワードの長さが重要になるのは、主にこのオフライン攻撃に耐えるためです。
長さと文字種から強さを計算する(エントロピー)
ランダムに作ったパスワードの強さは、「エントロピー」というビット数で表せます。使う文字の種類がN種類、長さがL文字なら、組み合わせの総数はN^L通りで、エントロピーは L × log2(N) ビットです。1ビット増えるごとに、総当たりに必要な試行回数は2倍になります。
- 数字のみ(10種類): 1文字あたり約3.3ビット
- 英小文字のみ(26種類): 約4.7ビット
- 英大文字・小文字・数字(62種類): 約5.95ビット
- 英大文字・小文字・数字・記号(ASCIIの印字可能文字94種類): 約6.55ビット
英大文字・小文字・数字の62種類で、1秒間に100億回推測できる攻撃者が総当たりした場合、見つかるまでの平均時間の目安は次のようになります。
長さ エントロピー 平均的な解読時間(毎秒100億回)
8文字 約48ビット 約3時間
12文字 約71ビット 約5,000年
16文字 約95ビット 約760億年文字の種類を増やすより、長さを増やすほうが効果が大きいことがわかります。62種類で8文字(約48ビット)から、94種類に増やしても約52ビットにしかなりませんが、62種類のまま12文字にすれば約71ビットになります。実際の解読速度はサービス側のハッシュ方式によって大きく変わりますが、ランダムな文字で12文字以上、できれば16文字以上を目安にするとよいでしょう。
ただし、この計算が成り立つのは、文字を完全にランダムに選んだ場合だけです。「Tanaka1985!」のように単語・名前・生年・記号を組み合わせた人間らしいパスワードは、4種類の文字を含んでいても、辞書攻撃ではずっと短時間で見つかってしまいます。
パスフレーズとパスワードのルールの最新の考え方
覚える必要があるパスワードには、ランダムな単語を複数つなげる「パスフレーズ」が向いています。例えば7,776語の単語リストからサイコロなどでランダムに6語を選ぶ方法(ダイスウェア)では、1語あたり約12.9ビット、6語で約77.5ビットのエントロピーになります。自分で単語を「思いつく」のではなく、ランダムに選ぶことが重要です。
パスワードのルールについての考え方も変わってきています。アメリカ国立標準技術研究所(NIST)のデジタルアイデンティティのガイドライン(SP 800-63B)では、文字種の組み合わせを強制するルールや定期的なパスワード変更の強制を求めず、長さを重視し、流出済みのパスワードやよく使われるパスワードを拒否することを推奨しています。2025年に公開された改訂版(SP 800-63B-4)では、パスワードだけで認証する場合は15文字以上を求めています。
定期的な変更を強制すると、「Password1」「Password2」のように規則的に少しずつ変えるだけになりがちで、かえって推測しやすくなるためです。パスワードの変更は、流出が疑われるときに確実に行うことが大切です。
使い回しが危険な理由と、パスワードマネージャーの活用
どれだけ強いパスワードでも、複数のサービスで使い回していると、そのうち1つのサービスから流出しただけで、すべてのアカウントが危険にさらされます。リスト型攻撃はこの使い回しを狙ったもので、自分にはどうにもできない「他社のサービスからの流出」がきっかけになる点が厄介です。
サービスごとに異なる長いランダムなパスワードを使うのが理想ですが、すべてを覚えるのは現実的ではありません。そこで役立つのがパスワードマネージャーです。
- サービスごとに十分な長さのランダムなパスワードを生成・保存できる
- 覚えるのはマスターパスワード(長いパスフレーズ)1つだけでよい
- 登録したドメインでのみ自動入力されるため、URLが微妙に異なるフィッシングサイトに気づきやすい
- ブラウザやOSに組み込まれたもの(Google パスワードマネージャー、iCloudキーチェーンなど)も利用できる
あわせて、重要なアカウントでは多要素認証(2段階認証)を有効にしましょう。パスワードが漏れても、スマートフォンの認証アプリやセキュリティキーがなければログインできなくなります。対応しているサービスでは、フィッシングに強い「パスキー」を使うのも有力な選択肢です。
このサイトのパスワード生成ツールでは、長さ(4〜128文字)と、英大文字・英小文字・数字・記号の使用有無を選んで、1件・5件・10件のパスワードをまとめて生成できます。乱数にはブラウザの暗号論的に安全な乱数(crypto.getRandomValues)を使い、選んだ文字種がそれぞれ1文字以上含まれるようにしています。4種類すべてを選んだ場合の文字は88種類で、16文字なら約103ビットのエントロピーになります。記号を使えないサービスでは、記号をオフにしてその分長くしてください。
開発者向け: パスワードを扱うときの注意点
サービスを作る側では、利用者のパスワードを平文で保存しないことはもちろん、SHA-256のような高速なハッシュ関数をそのまま使うのも不十分です。高速なハッシュは、オフライン攻撃で大量の候補を短時間で試せてしまうからです。
- パスワードの保存には、Argon2id・bcrypt・scryptなど、意図的に計算を重くしたパスワード専用のハッシュ関数を使う
- ユーザーごとに異なるランダムなソルトを付けて、同じパスワードから同じハッシュ値が生まれないようにする(上記の関数は自動でソルトを扱う)
- パスワードやトークンの生成には、暗号論的に安全な乱数を使う。JavaScriptの Math.random() やPythonの random モジュールは使わない
- パスワードの最大長を短く制限しすぎない(パスフレーズを使えるよう、少なくとも64文字程度は許可する)
import secrets
import string
alphabet = string.ascii_letters + string.digits
password = "".join(secrets.choice(alphabet) for _ in range(16))ハッシュ生成ツールで同じ文字列のSHA-256を何度か計算してみると、入力が同じなら常に同じ値になることが確かめられます。だからこそ、ソルトなしのハッシュでは、よく使われるパスワードのハッシュ値を事前に計算した表(レインボーテーブル)と照合するだけで元のパスワードがわかってしまいます。SHA-256などの汎用ハッシュは、ファイルの改ざん検知やチェックサムには適していますが、パスワードの保存には専用の関数を使いましょう。