Nucleus

ブルートフォースアタックを防ぐために

2007年12月3日

現在のところNucleusは、パスワードをMD5ハッシュ値として保存している。平文ではなくハッシュを用いているのは、万一サーバの保存データが洩れた場合に、容易ににパスワードを類推できないようにするためである。

ところが、先の記事で述べたように、たとえMD5の様なハッシュ関数を用いても、PS3のような演算速度の速いコンピューターでパスワードをはじき出すことが容易になってきた。MD5の代わりにSHA1のような新しいアルゴリズムのハッシュを用いても、解決にはならない。

王道の解決方法は、長いパスワードを用いることである。100文字ほどの長さのパスワードを用い、SHA1のような最新もしくはそれに順ずるアルゴリズムでハッシュ化すれば、ブルートフォースでパスワードを求めることは、現在の技術ではほとんど不可能になる。

ところが、パスワードを100文字にすると、それを入力するのが面倒くさいばかりでなく、パスワードの内容まで忘れてしまうことは頻繁に起こりうるだろう。そこで、どうすればよいか対策を考えてみた。

ハッシュ値が洩れるのは、ほとんどのケースでSQLインジェクションによるものと思われる。ならば、SQLインジェクションではデータが洩れないところにランダムな文字列を用意し、ユーザーが入力したパスワードと併せてSHA1関数を通せばよい。

SQLインジェクションではデータが洩れないところとは、Nucleusの場合だとconfig.phpが考えられる。このファイルの内容は、めったなことでは洩れないはず。逆に言うと、この内容が洩れるレベルまでハックされているとすれば、そのハッカーはすでにサーバの実行権限を奪取している可能性が高い。

インストールする際のinstall.phpに次のようなHTMLを挿入し、ランダムな100文字の文字列を作成する。この内容を、config.php に取り込むようにすれば良いのではないだろうか。

<html>
<body onmousemove="
  document.getElementById('result').value+=String.fromCharCode(((new Date()).getTime())%94+33);
">
<form>半角で100文字入力のでたらめな文字列をしてください。<br />
<input type="text" value="" name="result" id="result" size="120" maxlength="100" /><br />
<input type="reset" />
</form>
</body>
</html>

以下、上記スクリプトのデモ。
半角で50文字のでたらめな文字列を入力してください。



コメント

Kat (2007年12月5日 11:11:20)

次のwebサイトによると、

http://www.pcworld.com/article/id,140037/article.html

Breese was looking for a way to optimize processing to make MD5 calculations go very quickly, he says. MD5 (Message-Digest algorithm 5) is one of the most used cryptographic hash functions. The PS3 managed to conduct over 1.4 billion MD5 calculations a second, he says.

ということらしい。
  1秒間に14億回
  1日では120兆回
  1年では4京回
の計算になる。

Kat (2007年12月12日 15:21:39)

MD5/SHA1/SHA512でハッシュ値の計算速度を比べてみると、MD5とSHA1はほぼ同じで、SHA512はおおよそ5倍の時間がかかるという結果が出た。これは、PHPを用いて比較した(下記スクリプトを参照)が、アセンブラで書いたプログラムをPS3で実行してもほぼ同じ傾向であろう。8文字の英数字を含むパスワードの解析に、MD5/SHA1 でおおよそ2日、SHA512でも10日でよい計算だ。

(測定に用いたスクリプト)
<pre><?php
error_reporting(E_ALL);
$texts=array();
$data=array();
srand(time());
echo microtime()." - start\n";
for($i=0;$i<1000;$i++){
$texts[$i]='';
for($j=0;$j<1000;$j++) $texts[$i].=chr(rand(0,255));
}
echo $data[0]=microtime()." - random texts created\n";

$results=array();
for($i=0;$i<1000;$i++) $results[$i]=md5($texts[$i]);
echo $data[1]=microtime()." - md5 hashs calculated\n";
$results2=array();
for($i=0;$i<1000;$i++) $results2[$i]=$results[$i];
echo $data[2]=microtime()." - control routine terminated\n";

$results=array();
for($i=0;$i<1000;$i++) $results[$i]=sha1($texts[$i]);
echo $data[3]=microtime()." - sha1 hashs calculated\n";
$results2=array();
for($i=0;$i<1000;$i++) $results2[$i]=$results[$i];
echo $data[4]=microtime()." - control routine terminated\n";

$results=array();
for($i=0;$i<1000;$i++) $results[$i]=hash('sha512',$texts[$i]);
echo $data[5]=microtime()." - mdsha512 hashs calculated\n";
$results2=array();
for($i=0;$i<1000;$i++) $results2[$i]=$results[$i];
echo $data[6]=microtime()." - control routine terminated\n";

echo "Results (seconds to calcule 1000 times):";
echo "\nmd5   : ".(float)($data[1]-$data[0]-($data[2]-$data[1]));
echo "\nsha1  : ".(float)($data[3]-$data[2]-($data[4]-$data[3]));
echo "\nsha512: ".(float)($data[5]-$data[4]-($data[6]-$data[5]));

コメント送信