漏洩パスワード対策:Pwned Passwords APIの仕組みと実運用での注意点
作成日:2025.11.06
Pwned Passwords API(Have I Been Pwned)が採用する k‑Anonymity の仕組みを分かりやすく解説し、PHPによる実装例を通して漏洩パスワードチェックの具体手順を示します。さらに、ユーザー通知文面の注意点など、実運用で押さえるべきセキュリティと運用上の留意点をまとめています。
目次
Pwned Passwords API とは
Pwned Passwords API は、Have I Been Pwned (HIBP) の提供するAPIで、過去にデータ漏洩で公開されたパスワードが含まれているかどうかを確認するためのサービスです。このAPIを利用することで、ユーザーが入力したパスワードが既知の漏洩パスワードリストに含まれているかをチェックできます。
何故使うのか
多くのユーザーは、複数のサービスで同じパスワードを使い回す傾向があります。もし一つのサービスがデータ漏洩を起こした場合、そのパスワードが他のサービスでも悪用されるリスクがあります。
Pwned Passwords API を利用することで、ユーザーが安全なパスワードを選択する手助けができ、セキュリティ向上に寄与します。
Pwned Passwords API の仕組み
Pwned Passwords API は、k-Anonymity という技術を利用して、ユーザーのプライバシーを保護しながらパスワードの漏洩チェックを行います。具体的には、以下の手順で動作します。
- クライアント側でユーザーの入力したパスワードを
SHA-1でハッシュ化する。 - ハッシュ値の最初の5文字(プレフィックス)をAPIに送信する。
- APIは、そのプレフィックスに一致するハッシュ値のサフィックス(残りの部分)と、それに対応する漏洩回数を返す。
- クライアント側で、受け取ったサフィックスと、元のパスワードのハッシュ値のサフィックスを比較し、一致するものがあれば、そのパスワードは漏洩リストに含まれていると判断する。
この処理の流れで重要なポイントは、クライアント側から送信される情報も、APIから返される情報も、完全なパスワードのハッシュ値ではないため、第三者にパスワード(及びハッシュ値の全文)が漏洩するリスクが低い、ということです。
APIの利用方法
エンドポイント
Pwned Passwords API は、以下のエンドポイントを利用してアクセスします。
GET https://api.pwnedpasswords.com/range/{prefix}
※{prefix} は、ユーザーのパスワードを SHA-1 でハッシュ化した際の最初の5文字です。
レスポンス形式
APIのレスポンスは、テキスト形式で返されます。各行は、サフィックスと漏洩回数がコロンで区切られた形式になっています。
以下のような感じ。
0018A45C4D1DEF81644B54AB7F969B88D65:1
00D4F6E8FA6EECAD2A3AA415EEC418D38EC:2
011053FD0102E94D6AE2F8B83D76FAF94F6:1
...
想定されるユースケース
- ユーザー登録時のパスワード強度チェック
- 既存ユーザーのパスワード変更時の漏洩チェック
- 定期的なセキュリティ監査の一環としてのパスワード検証
など。
実装上の注意点
常に HTTPS を使う
APIへのリクエストは常に HTTPS を使用して行い、通信の安全性を確保しましょう。
User-Agent を必ずセットする
APIリクエストには、必ず適切な User-Agent ヘッダーを設定しましょう。これは、API提供者がトラフィックを監視し、悪意のある利用を防止するために重要です。
平文/フルハッシュをログや永続データに残さない
セキュリティ上の理由から、ユーザーの平文パスワードやフルハッシュ値をログやデータベースに保存しないように注意しましょう。
レートリミットに注意する
Pwned Passwords API にはレートリミットが設定されているため、過剰なリクエストを送信しないように注意してください。必要に応じて、リクエストの間隔を調整する、レスポンスをキャッシュする、などの対策を講じましょう。
APIレスポンスのキャッシュファイルの取り扱いにも注意が必要です。キャッシュファイルには漏洩パスワードのハッシュサフィックスが含まれているため、不正アクセスを防ぐために適切なアクセス制御を行い、不要になったキャッシュは速やかに削除することをお勧めします。
また、キャッシュファイルの名前に、ハッシュのプレフィックスをそのまま使用したりすると、ファイル名+ファイル内容から元のパスワードが推測されるリスクがあるため、ファイル名をランダムな文字列に変更する、あるいは暗号化するなどの対策を講じることも検討してください。
必要ならオフライン版データをローカル運用
既存ユーザーのパスワードの一括チェックなど、大量のパスワードを確認する必要がある場合は、Pwned Passwords のオフライン版データをダウンロードしてローカルで運用することも検討してください。これにより、APIへの負荷を軽減し、レートリミットの問題を回避できます。
サンプルコード(PHP)
<?php
$password = "1234567890"; // ユーザーの入力したパスワード
$sha1 = sha1_upper($password); // SHA-1でハッシュ化(大文字)
$prefix = substr($sha1, 0, 5); // ハッシュの最初の5文字を取得
$suffix = substr($sha1, 5); // 残りの部分を取得
$result = haveibeenpwned_api_request($prefix); // APIリクエストを送信
$lines = explode("\n", $result); // レスポンスを行ごとに分割
$pwned = 0;
// 各行をチェックして、該当するハッシュのサフィックスが存在するか確認
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
list($hash_suffix, $count) = explode(":", $line);
if(strcasecmp($hash_suffix, $suffix) === 0) {
$pwned = $count;
break;
}
}
if ($pwned > 0) {
echo "このパスワードは過去に {$pwned} 回漏洩しています。別のパスワードを使用してください。\n";
} else {
echo "このパスワードは漏洩していません。\n";
}
// SHA-1でハッシュ化(大文字)する処理
function sha1_upper($password) {
return strtoupper(sha1($password));
}
// Have I Been Pwned APIにリクエストを送信する処理
function haveibeenpwned_api_request($prefix) {
$prefix = strtoupper($prefix);
// キャッシュファイルが存在し、1時間以内に更新されている場合はキャッシュを使用(今回は省略)
// cURLでAPIリクエストを送信
$url = 'https://api.pwnedpasswords.com/range/' . $prefix;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_USERAGENT => 'MyAppName/1.0 (dample@abe-tatsuya.com)',
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
]);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $code != 200) {
// エラーハンドリング(今回は省略)
}
// レスポンスをキャッシュファイルに保存(今回は省略)
return $response;
}
ユーザーへの通知文面を検討する
これは技術的な話とは別レイヤーの問題ですが、ユーザーに対してパスワードが漏洩している場合の通知文面を慎重に検討する必要があります。
例えば、
あなたの入力したパスワード「hogehoge」は、漏洩しています。
のようなシンプルな通知は最悪です。
- 平文のパスワードをそのまま表示してしまっている
- 説明が不十分なため、「今この瞬間に漏洩した」と誤解される可能性がある
- ユーザーに不安を与えるだけで、具体的な対応策が示されていない
などなど、問題が多すぎます。
運用しているサービスが toC なのか、 toB なのか、あるいは inB なのか。ユーザー層の技術・セキュリティリテラシーはどの程度か、などによって、最適な通知文面は変わってくると思いますが、以下のようなポイントを押さえた文面を検討すると良いのではないでしょうか。
- 文面内に平文のパスワードを含めない(大前提)
- 漏洩データベースに含まれているパスワードであることを明示する
- 今この瞬間に漏洩したと誤解されない文面にする
- 具体的な対応策(例:別のパスワードを使用する、多要素認証を有効にする等)を示す
まとめ
Pwned Passwords API は、ユーザーのパスワードが過去に漏洩したことがあるかどうかを確認するための強力なツールです。適切に実装し、ユーザーに対して適切な通知を行うことで、サービスのセキュリティを向上させることができます。
ただし、APIの利用にあたっては、セキュリティ上の注意点を十分に理解し、適切な対策を講じることが重要です。
最後に、APIの詳細な仕様や最新情報については、公式ドキュメントを参照してください。
奈良市を拠点に、26年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。
これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。
【制作会社・企業様向けサポート】
Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。
ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。
Composerオートローダーでの「Class not found」エラー対処法
2025.10.18
Composerを利用してPHPライブラリをインストールした後に発生する「Class not found」エラーの原因と、その対処法について解説しています。特に、オートローダーの設定が正しく機能していない場合の具体的なエラー例を基に手順を紹介。
PHPで実現するCloud Vision API OCR入門:画像からテキスト抽出の基本
2025.09.30
Google Cloud Vision API を利用して、PHP で画像からテキストを抽出する OCR 処理の基本的な実装方法を解説します。API の有効化や認証情報の取得、PHP クライアントライブラリのインストール手順から、実際のコード例に基づいた OCR 処理の流れを紹介。
onelogin/php-samlで実現するPHP SAML認証:基本設定から動作確認まで
2025.09.25
軽量ライブラリである onelogin/php-saml を利用して、PHPでSAML認証を実装する方法を詳しく解説します。Composerによるインストールから、証明書・秘密鍵の準備、設定ファイルの作成、そしてSPのメタデータ生成やSSO・ACSの各スクリプトまで、SAML認証の基本設定と動作確認の一連の流れをサンプルコードを交えて紹介。
PHPで実現するHTML目次自動生成:見出しタグ抽出と目次リンクの出力
2025.07.31
PHPを活用して、HTML文書から見出しタグを抽出し、目次リンクを自動生成する方法を解説します。見出しに自動でIDを付与する仕組みや、抽出した情報をリスト形式で出力するサンプルコードを紹介。効率的なドキュメント構造の整備とSEO対策に繋がる実践的な手法を、わかりやすくまとめています。