こんにちは!新人IT担当者の皆さん、そしてセキュリティの世界に一歩を踏み出した開発者の皆さん、日々の業務お疲れ様です。
いきなりですが、皆さんは普段どんなパスワードを設定していますか?「覚えやすいから」「面倒だから」といって、自分のペットの名前や、どこかで使い回している短いパスワードをそのまま登録していませんか?
実は、その何気ないパスワードの選び方が、会社のシステムやユーザーの大切な個人情報を守れるかどうかの分かれ道になるんです。今回は、サイバー攻撃者がどのようにパスワードを狙っているのか、そしてそれをどうやって鉄壁の防御で守るのかを、身近な「家の鍵」にたとえながら、一緒に優しく紐解いていきましょう!
—
1. 泥棒(攻撃者)は、どうやってあなたの家(システム)を狙うのか?
セキュリティの世界では、システムに侵入しようとする悪意ある人を「攻撃者」と呼びます。彼らは映画に出てくるような天才ハッカーで、一瞬でパスワードを当てる魔法の杖を持っているわけではありません。
実は、彼らがやっていることはとっても泥臭くて、そして非常に効率的な「総当たり攻撃(ブルートフォースアタック)」や、あらかじめ用意されたよくあるパスワードリストをしらみつぶしに試す「辞書攻撃」なんです。
これを身近な例にたとえてみましょう。
- 短いパスワード(例:
abcや12345)
これはまるで、「ダイヤルが3桁の小さな南京錠」のようなものです。泥棒がガチャガチャと手動で回しても、数秒、あるいはコンピュータを使えば一瞬で開いてしまいますよね。
- 複雑で長いパスワード(例:
K9#m$P2!vL9qなど)
これは、「数万通りの組み合わせがある最新式の頑丈な暗証番号付きドアロック」のようなものです。しかも、どれだけ力任せにガチャガチャやっても、システム側が「あ、コイツ不審な動きをしているな」と気づいてロックしてくれる仕組み(ストレッチングなど)が裏で働いています。
つまり、パスワードの「長さ」と「複雑さ」は、そのまま泥棒が侵入にかける「時間と手間(コスト)」に直結するんです。攻撃者はビジネスとして動いていますから、開けるのに何百年もかかるような頑丈なドアの前では、面倒になって諦めて別のターゲットに移ってくれます。
—
2. パスワードは「そのまま」保存してはいけない?ハッシュ関数の正体
さて、ユーザーが「すごく頑丈なパスワード」を決めてくれたとします。では、私たち開発者はそのパスワードをデータベースにどうやって保存すればいいのでしょうか?
「データベースにそのまま文字として保存しておけばいいのでは?」……と思ったそこのあなた!それは絶対にやってはいけないNG行動です。もしデータベースが万が一サイバー攻撃にあって中身が盗まれてしまったら、ユーザーのパスワードが世界中に丸見えになってしまいますよね。
そこで登場するのが、「ハッシュ関数(SHA-2やSHA-3)」という仕組みです。
ハッシュ関数とは、どんなに長い文章やパスワードを入れても、まるでシュレッダーにかけたかのように、全く規則性のない「ランダムな文字列(ハッシュ値)」に変換してくれるマジックボックスのようなものです。
例えば、パスワードの password123 をハッシュ関数に通すと、こんな感じの文字列に変わります。
> ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f (※実際はもっと複雑です)
このハッシュ関数のすごいところは、「元のパスワードに戻すことが絶対にできない(不可逆性)」という点です。泥棒がデータベースを盗み見ても、このランダムな文字列から元のパスワードを推測することは原理的に不可能です。
システムは、ユーザーがログインしようとしたときに入力されたパスワードを再びハッシュ関数に通し、データベースにあるハッシュ値と「一致するかどうか」だけをこっそり確認しています。
—
3. でも、ハッシュ化だけではまだ危ない?「レインボー攻撃」の脅威
「じゃあ、ハッシュ化しておけば完璧だね!」……と言いたいところですが、セキュリティの世界はそんなに甘くありません。
攻撃者たちは、よく使われがちなパスワード(123456 や password など)をあらかじめ何億通りもハッシュ関数に通して、「パスワードとハッシュ値のペア一覧表(レインボーテーブル)」という辞書を作っています。これを使えば、盗んだハッシュ値と辞書を見比べるだけで、一瞬で元のパスワードを見つけ出せてしまうのです。
そこで私たちが使うのが、「ソルト(Salt)」と「ストレッチング(Stretching)」という、いわば二重の防犯対策です。
- ソルト(Salt = 塩):
パスワードをハッシュ化する直前に、ユーザーごとに違うランダムな文字列(おまじない)をくっつけます。こうすることで、たとえ同じ「password123」というパスワードを使っている人が二人いても、生成されるハッシュ値は全く別のものになり、先ほどの辞書攻撃が使えなくなります。
- ストレッチング(Stretching = 引き伸ばす):
ハッシュ関数をわざと何万回も何十万回も繰り返し実行させます。これによって、ハッシュ値を計算するのにほんの少しだけ(例えば0.1秒ほど)時間がかかるようになります。私たち人間にとっては気にならない待ち時間ですが、何億回もパスワードを総当たりで試したい攻撃者にとっては、時間がかかりすぎてパソコンが焼き切れてしまうほどの致命的な嫌がらせ(=攻撃コストの増大)になります。
—
4. 【実践】安全なパスワード保存のコード例(PHP)
それでは、ここまでお話した「ハッシュ化」「ソルト」「ストレッチング」をすべて自動で安全に行ってくれる、現代のWeb開発における最強の味方、PHPの password_hash() 関数を使った実装例を見てみましょう。
PHPでは、内部で自動的に安全なソルトを生成し、適切なストレッチング(BcryptやArgon2といったアルゴリズム)を行ってくれます。
<?php
/**
* ユーザー新規登録時のパスワード保存処理
*
* 新人エンジニアの皆さん、パスワードを生のままDBに入れてはいけません!
* 常に安全なハッシュ関数を使って保存しましょう。
*/
// 1. フォームから送信されてきたユーザーの入力値(本来はバリデーションを行います)
$raw_password = 'User_Secure_Password_123!';
// 2. パスワードを安全にハッシュ化する(自動でソルト生成&ストレッチングを実行)
// PASSWORD_DEFAULTを指定しておけば、PHPのバージョンアップに合わせて最も推奨される最新のアルゴリズムが使われます。
$hashed_password = password_hash($raw_password, PASSWORD_DEFAULT);
/*
* データベースへの保存イメージ:
* この $hashed_password をそのままデータベースのユーザーテーブルに保存します。
* 中身には自動生成されたソルトやストレッチングの回数情報も含まれているため、
* 別途ソルトを管理する必要はありません。
*/
echo "データベースに保存する値: " . htmlspecialchars($hashed_password, ENT_QUOTES, 'UTF-8') . "\n";
続いて、ユーザーがログインする際のパスワード検証のコードです。
<?php
/**
* ログイン時のパスワード検証処理
*/
// ユーザーがログイン画面に入力したパスワード
$input_password = 'User_Secure_Password_123!';
// データベースから取り出したハッシュ化済みのパスワード(擬似的に上記の値を使用)
$stored_hash_from_db = '$2y$10$e0MYzXyjpJS7Pd0RVvHwHe... (DBに保存されていた文字列)';
// password_verify() を使って安全に照合する
// 入力されたパスワードを同じアルゴリズムでハッシュ化し、DBの値と安全に比較します(タイミング攻撃対策も内蔵されています)
if (password_verify($input_password, $stored_hash_from_db)) {
echo "ログイン成功!ようこそお帰りなさいませ。";
} else {
echo "パスワードまたはメールアドレスが間違っています。";
}
このように、フレームワークや言語が提供する標準的でモダンな関数(PHPなら password_hash()、Pythonなら bcrypt や argon2 ライブラリなど)を正しく使うことで、複雑な暗号理論を自前で実装することなく、強固なセキュリティを担保することができます。
—
5. まとめ:一歩ずつ、確実なセキュリティを
いかがでしたでしょうか?
パスワードの複雑性要件(長さや文字種)と、ハッシュアルゴリズム(ソルトやストレッチング)は、どちらか片方だけが強固でも意味がありません。
- 長い・複雑なパスワードで、泥棒が侵入する手間を限界まで増やす。
- ソルトとストレッチングを伴う強力なハッシュ化で、万が一の盗難時にも中身を絶対に読ませない。
この両輪が揃ってはじめて、私たちのシステムは安全な要塞になります。
最初は覚えることが多くて大変に感じるかもしれませんが、「どうすれば泥棒(攻撃者)にとって一番面倒くさい状況を作れるか?」という視点を持つと、セキュリティ対策はぐっと面白くなりますよ。
一歩ずつ、確実に安全なコードを書けるエンジニアを目指して一緒に頑張っていきましょう!それでは次回の記事もお楽しみに!
コメント