Have I Been Pwned(HIBP)で定期的にメールアドレスの流出チェックをしているが、2019/1に流出したCollection #1に、メールアドレスが含まれていた。
併せてパスワードも流出しているということで、チェックしようと思ったが、パスワードマネージャーとして使用しているKeePassには100件以上登録しているので面倒。
とりあえずHIBP運営者のTroy Huntさんのブログを見ていたら、1PasswordのWatchtower機能にHIBPのAPIが統合された、という記述を発見。
APIがあるならパスワード全部チェックできるかと思い、試したのが2019/1月末。備忘のためメモ。
HIBP APIの確認
HIBP APIの現在のバージョンは2。匿名性モデルに沿って実装されており、生パスワードは送信されない。
パスワードAPIの使い方は、以下のようになる。
- UTF-8でエンコードされたパスワードをSHA1ハッシュに変換
https://api.pwnedpasswords.com/range/{SHA1ハッシュの先頭5文字}
にGETリクエストを送信{送信した5文字から始まるSHA1ハッシュの残り35文字}:流出数
が返る、アルファベットは大文字
Git Bashと付属のOpenSSL、grepを使い、最弱のパスワードとしておなじみの「123456」で試してみる。
# OpenSSLで生成したハッシュのアルファベットは小文字なので、grepではiオプションで大文字小文字を無視させる DIGEST=$(echo -n 123456 | openssl sha1 | cut -d ' ' -f 2) curl -sS https://api.pwnedpasswords.com/range/${DIGEST:0:5} | grep -i ${DIGEST:5} # D09CA3762AF61E59520943DC26494F8941B:23174662
2,300万回...
KeePassからのパスワードエクスポート
File > Exportからエクスポートできる。
CSVでエクスポートすればいいと思ったが、「KeePass CSV (1.x)」を選択すると、インポート/エクスポート用のためか、すべての項目が出力されてしまう。
Notesに改行など入っているため、パスワードの抽出が面倒。
また、パスワード以外にもカード類の暗証番号や、秘密の質問の答えなどを管理しているため、それらは除外したい。
「Customizable HTML File」を選択すると、パスワードがcodeタグで囲まれたUTF-8のHTMLを出力できる。
Layoutの設定はデフォルトで出力して、Google Chromeで開き、デベロッパーツールで以下のJavaScriptを実行して、必要なパスワードをクリップボードにコピー。
const ta = document.body.appendChild(document.createElement('textarea')); Array.from(document.querySelectorAll('code'), c => c.textContent) .filter(p => p.length > 4 && p.match(/^[\x20-\x7e]+$/)) .forEach(p => ta.value += p + '\n'); ta.select(); document.execCommand('copy');
適当なファイルにペーストして保存しておく。
生パスワードをクリップボードにコピーしたり、保存したりはまずいが、エクスポートの段階で保存されているので妥協。
ハッシュ化するライブラリを読み込めば、JavaScriptで直接APIを実行するのは難しくないだろう。
エクスポートしたパスワードの流出チェック
ファイルからパスワードを読み込むように、シェルスクリプトを修正。
INPUT_FILE=... RESULT_FILE=... # 進捗状況確認用 LINE_NUMBER=1 # 連続でアクセスするのは悪いので、適当に待機 WAIT_SECOND=5 echo 'start...' while read RAW_PASSWORD; do DIGEST=$(echo -n ${RAW_PASSWORD} | openssl sha1 | cut -d ' ' -f 2) RESULT=$(curl -sS https://api.pwnedpasswords.com/range/${DIGEST:0:5} | grep -i ${DIGEST:5}) if [ -n "${RESULT}" ]; then echo "${LINE_NUMBER},${RESULT#*:}" >> ${RESULT_FILE} fi echo "${LINE_NUMBER} checked." let LINE_NUMBER++ sleep ${WAIT_SECOND}s done < ${INPUT_FILE} echo 'end.'
試しに、2018年のパスワードワースト10で実行してみる。
123456 password 123456789 12345678 12345 111111 1234567 sunshine qwerty iloveyou
さすがの結果に。中でも「123456」は、まさに桁違い。
1,23174662 2,3645804 3,7671364 4,2889079 5,2333232 6,3093220 7,2484157 8,405578 9,3810555 10,1593388
感想
事前認証やHTTPヘッダーの設定なども不要で、簡単に使用できた。
確認の結果、現在使用しているパスワードは流出していなかったので一安心。