ホームページビルダーの機能の1つである、パスワード付きリンクの暗号についてあれこれ。
2008/08/18
Webサイト作成のためのツールの1つであるホームページビルダーには、パスワード入力によって隠しページを作る機能がついている。これを、パスワード付きリンクと呼ぶ。
この機能は隠したいページのファイルパスを特定のパスワードで暗号化し、パスワード入力画面で正しいパスワードを入力すれば、正常にファイルパスが解凍され隠されたページにジャンプすることができる、というものだ。従ってこれは単なる隠しページに過ぎず、サーバー側の認証で閲覧を許可するような正規の制限ページではない。
2008/08/18
このパスワードリンクは隠しているページのファイルパスの他に、正しいパスワードを認証するためにパスワード自体も同一の方法で暗号化されている。ファイルパスだけを暗号化し、パスワードが違った場合も間違ったページにジャンプさせるのであれば、この暗号は安全と言ってよい。しかし、パスワードをパスワード自身で暗号化している以上、何らかの脆弱性が存在する恐れがある。
そこで、このパスワード付きリンクの安全性を維持するために必要な、ファイルパスに対するパスワードの条件を考えることにする。
2008/08/18
このパスワードリンクの暗号解読機構は、驚くほど単純な構造になっている。1つは、入力したパスワードの各文字が、複合化する文字列の各文字に1対1対応している点。1つは、その解読が単なる加減算のみに基づいている点だ。
具体的な仕組みを述べる。先ず、暗号化されている文字列の中身は
[ファイルパス][パスワード]
のように、ファイルパス+パスワードの順番で並んでいる。
次に、この文字列に対応する複合化用の文字の対応関係は、例えば暗号文をFをファイルパス部分、Pをパスワード部分とした15桁のFFFFFFFFFPPPPPPとして表し、パスワードをabcdefの6文字と仮定すると、
i | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 12 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
j | 6 | 5 | 4 | 3 | 2 | 1 | 6 | 5 | 4 | 3 | 2 | 1 | 6 | 5 | 4 |
暗号文 ENC(i) | F | F | F | F | F | F | F | F | F | P | P | P | P | P | P |
パスワード PWD(j) | f | e | d | c | b | a | f | e | d | c | b | a | f | e | f |
となる。ただし。i,jは序数、ENC(i)は前からi番目の暗号文の文字を、PWD(j)は前からj番目のパスワードの文字を表す。このとき複合化されたデータは、暗号文/パスワードの文字を特定の法則に従って数字に直したものについて
複合化された文字 = ENC(i) - PWD(j) - j
で表される。
文字を数字に直す方式は使用されている
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
の95文字の各文字を、この並び方における先頭を0として数えたときの位置として変換する。
複合化された文字の数値が負であった場合、正になるまで95を足すことによって正の数に補正する。この操作は95を基数とした系を意味している。
2008/08/18
この暗号方式は、複合化に用いる数字が一連の操作で一切続けて使用されない、単純な形式になっている。ファイルパスの部分は分からないものとして考えるしかないため、暗号文後半のパスワードがパスワード自身を複合化する部分を狙う他ない。幸いにも複合化の操作は単純な加算に基づく。
上の例で例えると、パスワードの部分は
i | 10 | 11 | 12 | 12 | 14 | 15 |
---|---|---|---|---|---|---|
j | 3 | 2 | 1 | 6 | 5 | 4 |
暗号文 ENC(i) | P | P | P | P | P | P |
パスワード PWD(j) | c | b | a | f | e | f |
複合化結果 | a | b | c | d | e | f |
のようになる。この場合だと、パスワードを未知数PWD(i)とした方程式が
PWD(i-9) = ENC(i) - PWD(j) - j
即ち
PWD(1) = ENC(10) - PWD(3) - 3 PWD(2) = ENC(11) - PWD(2) - 2 PWD(3) = ENC(12) - PWD(1) - 1 PWD(4) = ENC(13) - PWD(6) - 6 PWD(5) = ENC(14) - PWD(5) - 5 PWD(6) = ENC(15) - PWD(4) - 4
の6本の方程式で表される。これを変形すると
PWD(i-9)+PWD(j) = ENC(i) - j PWD(1)+PWD(3) = ENC(10) - 3 PWD(2)+PWD(2) = ENC(11) - 2 PWD(3)+PWD(1) = ENC(12) - 1 PWD(4)+PWD(6) = ENC(13) - 6 PWD(5)+PWD(5) = ENC(14) - 5 PWD(6)+PWD(4) = ENC(15) - 4
が得られ、パスワードが決まってしまう部分が2箇所、左辺が同一になる部分が2組4箇所出来上がる。
つまり、6文字だと仮定した場合、この時点で2文字のパスワードの文字列が解読され、残りの4文字も2組の対で表されてしまう。
更に注意したいのは、組になっている2本ずつの式。これは
ENC(10) - 3 = ENC(12) - 1 ENC(13) - 6 = ENC(15) - 4
という式を与え、パスワードが6文字であるという仮定が正しいことを証明するには、この方程式が正しくなることを調べればいい。もし等式が一致するような場合が、正しい文字数を除いて存在しないならば、ここまでの段階でパスワードの2文字が特定され、パスワードの長さも特定できてしまう。
その上、パスワードの2文字が1本の式を満たすという事態は、状況を更に悪くする。もしファイルパスの何文字かが推測できてしまうと、関係式から最大で推測された文字の2倍のパスワードが特定されてしまう。例えばファイルパスの終端文字列が.htmlであると推測したとき、その2倍に当たる実に10文字のパスワードが特定できる。最悪の場合、この.htmlの露呈のみで12文字のパスワードが判明する。これは、大抵の場合パスワードが全て特定される状況だ。
この仮定は、パスワードの長さが一意的に決まってしまう状況を想定している。ただし、仮にそうでなかったとしても、パスワードの長さは暗号文自体より短い以上、候補は高々10種類・20種類程度に絞られる。尚、手元の実験では殆どの場合で、パスワードの長さは1文字と2文字の場合を除けば2通り以内に特定されてしまった。
パスワードが正しいことを判定する式は、上記の方程式が全てだ。パスワード長を特定できたとしても、例えばパスワードが10桁の場合、そのうち5桁は他の5桁と等式関係を持っており、10桁の数字が5桁の数字によって定まることを意味する。これは、悪く言えばパスワードの文字数が半分になってしまい、良く言えば一致判定を通る間違ったパスワードが実に5桁も存在することを意味する。総当り(ブルーフォース)攻撃で一致するパスワードを探そうとすると、文字単位の総当り方式では10桁パスワードの場合、その半分の5桁分に相当する955=7737809375個の候補がヒットしてしまう。何より、一致する条件が判っている以上、この7737809375種類は必ず見つけることができる。
総当りによるパスワードの検索は、200 OKを返すURIを総当りで検索することに等しく、事実上有効ではないことになる。
このことから、このパスワードリンクの性質が明らかになる。即ち
人力によるパスワード入力では、統計的に見てほぼ100%の確率で一致判定が成功するのに対し、機械による総当りでは一致判定を通ってしまう"ダミーパスワード"が1よりも十分多く存在する。
2008/08/18
以上の内容をまとめよう。先ず、確実に特定されてしまう情報は
次に、推論を許した場合特定される情報は
これは例えば
ことを意味する。大抵のパスワードは10文字前後のため、推測できる文字を使うことは致命傷に等しい。
総じて、安全なパスワードリンクのために必要なことは次のようになるだろう。
最初に触れたように注意したいのは、このパスワードリンクはサーバー側で認証を行う正規のものではなく、あくまでJavaScriptによる簡易なものに過ぎない。その上、上記のような欠点が幾つかある以上、このパスワードリンクでは重要な情報を保護できない。
2008/08/19
上記の理論に基づいて、パスワードリンクのサンプルデータを作成するスクリプト、生成済みの暗号データの脆弱性を調べるスクリプトを作成した。たかが5文字の推測でどれだけのパスワードが割れてしまうのか、実験されたし。
ビルダーと互換性を持った暗号の作成スクリプト。一々サンプル作るのにビルダーを使うのは億劫、簡単なテスト機能もついている。
※初期設定で暗号を作り、初期設定のパスワードとは全く違う文字「k」で複合化テストを試みると、なんとパスワードが一致してしまう。総当り検索では、このような偽パスワードが大量に検出され、使い物にならない。
.htmlが末尾(変更可能)にあると仮定した場合のパスワード文字を可能な限り解析するスクリプト。1次解析の結果までで0〜2文字が決定されてしまうため、0文字(なければ1文字)になるようなパスワードの長さを選ぶと良い。2次解析では文字列推測でhttp://、.htm、.htmlが定まるだけで、最大で10文字、平均すると7文字が決まってしまうため、拡張子を外すか、15文字を超える十分に長いパスワードを使用すると良い。
未特定の文字は"_"で、特定されてしまった文字は"*"で表示される。尚、この解析スクリプトは実際の文字列を求めるようには作られていない。