パスワードを忘れないようにブログに書いておく。

セキュリティの問題で今まで躊躇してたMoneyForward をついに始めた。 せめてものリスクを最小化するために、MFと銀行口座のパスワードを、推測できないランダムな文字列にすることにした。

しかしながら、Webサイトごとに異なるランダムな文字列を全て覚えるのは現実的ではないため、パスワードマネージャを用いる必要がある。 主なパスワードマネージャには、次のような物がある:

  1. ローカルのパスワードマネージャ (例: Mac の KeyChain など)
  2. クラウドのパスワードマネージャ (例: 1Password など)

1 は、他のデバイスとパスワードが共有できないため、不便である。 2は、クラウドにパスワードを預けることはやはり漏洩のリスクが伴うし、クラウドサーバーが落ちるとログインできなくなってしまうおそれがあるなど、 自分の手の届かないところが単一障害点となってしまうことが問題である。

そこで、

  • サイトごとのパスワードを、マスターパスワードとURLのハッシュで生成する
  • 生成ロジックを、ブログ等で大々的に公開する

ことで、サーバーが落ちた場合でも、マスターパスワードから生成ロジックによってパスワードを再生成できるようにすることを考える。

パスワード生成スクリプトは↓に公開した1

Password Generator

embeded page

スターパスワードの作成

この方法で大切になるのはマスターパスワードの安全性である。 人間、そこまでランダムな文字列というものは作れるものではないし、完全にランダムな文字列は覚えづらい。 そこで、文字のマトリクスを作り、そこに図形を描いて覚えるようにする。

スターパスワードの生成

  1. 任意の文字列(seed) を入力する。
  2. seed のSHA256 ハッシュ値Base64( RFC4648 )エンコードで求める。
  3. 得られたBase64文字列を7文字ずつ改行して 7×6+2 (最後の文字は=) のマトリクスを作る。
  4. マトリクス上で図形を描き、描いた位置の文字を拾って、マスターパスワードとする。

seed の値は秘密にする必要はない。例えば、yyyymmdd形式で表した生年月日を用いる。

得られるマトリクスは、例えば、seedが空文字列の場合、次のようになる。

$ openssl dgst -sha256 -binary /dev/null | base64 | fold -7 | sed -e 's/./ &/g'
 4 7 D E Q p j
 8 H B S a + /
 T I m W + 5 J
 C e u Q e R k
 m 5 N M p J W
 Z G 3 h S u F
 U =

当然であるが、マトリクスの上に描く図形はなるべくランダムで覚えやすいものとする。 私の場合、何故か覚えている子供の頃の実家のトイレの壁の汚れの模様を意匠化したものとした。 (実家のトイレはリフォームしたので、その壁の汚れはもう残っていない。)

スターパスワードの長さは14文字以上にする。 詳しくは後述する。

サイトごとのパスワードの生成

サイトごとのパスワードは、 サイトのFQDN (URL の https://xxxx/bbb の xxx の部分) とマスターパスワードからハッシュ関数により生成する。

サイトパスワードの生成

  1. HTTPS サイトのSSL証明書に記載されている FQDN を、マスターパスワードによって N=1000回 SHA-256 HMACをとる。
  2. 得られたハッシュ値Base64 エンコードし、サイトで利用可能な最大長を超えない4の倍数の長さの部分文字列をパスワードとする。

このようにサイトのパスワードを作成することで、 あるサイトのパスワードが漏洩した場合でも別のサイトのパスワードが推測されることはないうえ、 マスターパスワードさえ忘れなければ何度でも再生成できる。

スターパスワードの長さ

スターパスワードは何文字以上が良いであろうか。 あるサイトのパスワードが漏洩した場合でも、マスターパスワードや他のサイトのパスワードが実質的に漏洩しない安全性が必要である。

SHA-256 はBitcoin のPoWで使われていることでも有名である。 つまり、SHA-256 ハッシュの計算量はマイニングパワーとして取引されており、 「1ハッシュ=〇〇円」という値段がついている。

このサイトによれば、 1ギガハッシュ/秒で1週間マイニングすると、平均0.006559ドル(≒0.7円)の報酬が得られるという計算になる。 つまり、ビットコインをマイニングすれば、1 [GH/s] ÷ 0.7[円/週] = 8.6 \times 10^{14} ハッシュごとに、約1円の報酬が得られることになる。

私の資産(高々数百万円)をリスクを犯して奪うために、1億円分の計算をすることは考えられないため、 P = 8.6 \times 10^{14} \times 10^{8} 回のハッシュ関数を計算しなければ破れないパスワード長とすればよい。

seed によって異なるが、マトリクスに現れるunique な文字の種類は30種類程度なので、長さLのマスターパスワードは 30^{L}通りである。サイトのパスワードを1回計算するのに、N=1000回のハッシュ計算が必要なので、

 30^{L} \times N \geq P

 L \geq \log(P/N) / \log(30) \approx 13.5

よって、マスターパスワードは14文字以上が安全である。

資産がもっと多いよって人は、 \log_{10}(30) \approx 1.477 なので、 資産が3桁増えるごとにマスターパスワード長の下限を2文字増やすとよい。


  1. このスクリプトは、ブラウザ上だけで動作し、最初にスクリプトをロードする以外には一切の通信を行わない。万全を期すためには、「プライベートブラウジング」モードで上記ページを開き、インターネット接続を切ったうえでパスワード生成を行い、ブラウザを閉じてから接続を再開すると良い。