プロが教えるわが家の防犯対策術!

MySQLのDBにMD5でハッシュ化されたパスワードが格納されているのですが、これをPerlのスクリプトで照合したいと思っています。

具体的には、DBに格納されているパスワードを用いて、Perlで作成された会員専用ページなどにログインをするといった感じです。

DBIを用いてDBからの情報を取得することはできたのですが、Perl側での対処がわかりません。
Perl側で入力されたパスワードをハッシュ化して、双方を照合するなどの情報を見たのですが、いまいち解らず認証することができませんでした。

以下にパスワードに関する部分のソースを記載させていただきます。

srand();
@salt = ( "A".."Z", "a".."z", "0".."9", ".", "/" );
$salt = '$1$' . join('', map($salt[int(rand(64))], 1..8)) . '$';

$pass = crypt($in{'pass'}, $salt);

crypt($in{'pass'},$ary) eq "$ary")

※$aryはDB内に格納されているパスワードです

Perlに関して殆ど解っていないもので、とんちんかんな記述かもしれませんが、ご教授いただけますと幸いです。
宜しくお願いいたします。

A 回答 (3件)

ANo.2です。


SALT生成が必要なのはDB格納用に最初にエンコードする場合のみです
ご質問の内容の場合、すでにエンコードされたものは配列に格納されておりますのでSALT生成は不要です。(まずは処理の内容をしっかりと把握・整理してください)
チェックのみの処理手順なら以下のようになります。($aryは$ARYとしました)
## ***************************************************************
## DB比較プログラム
## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
## PWを取得(フォームからですね?)
my $inPW = '';
## DBから全PWを配列に格納
my @ARY = (???????????????);
## チェック用フラグ初期化
my $FLG = "false";
## 全配列をチェック
foreach my $V (@ARY){
## 暗号化パスワードから先頭2文字(SALT部分)を取り出す
my $sSALT = substr($V,0,2);
## 取得したSALTから
my $sPWD = crypt($inPW, $sSALT);
## 比較
if($sPWD eq $V){
$FLG = "true";
last;
}
## ------------------------------------------
## 上記ループ内処理の省力版:cryptは先頭2文字しか使わないのでわざわざ取り出さなくても良い
## ------------------------------------------
## my $sPWD = crypt($inPW, $V);
## if($sPWD eq $V){
## $FLG = "true";
## last;
## }
## ------------------------------------------
}

## 結果表示
if($FLG eq 'true'){
print "パスワードOK";
}else{
print "パスワードが不正です。";
}
## ***************************************************************

蛇足ながら、SALT生成が適用される新規パス登録の流れが以下のようになります。
## ***************************************************************
## DB登録プログラム
## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
## PWを取得(フォームからですか?)
my $inPW = '';
## 塩の生成
srand();## 乱数の種仕込み
my @sTABLE = ( "A".."Z", "a".."z", "0".."9", ".", "/" );## 乱数用→文字列置換テーブル
my $sSALT = join('', map($sTABLE[int(rand(64))], 1..2));## ランダムな文字列を2文字生成
## パスワードエンコード
my $sPWD = crypt($inPW, $sSALT);
## パスワードから暗号化された文字列をDBに登録する処理:$sPWD
??????????????????????????????????????????????????
## ***************************************************************

コメントから処理の流れを読み取ってください。
あと、これが表示されるHTMLの処理によって先頭の半角スペースが無視されますが、本体への「インデント」は忘れないようにしてください。
    • good
    • 0

この質問サンプルから想像した場合は、「salt」がランダムに生成エンコードされDB格納となっておりますので、DBに対しての直検索は出来ないと思います。


DB内から全ハッシュ値データを取得して、各ハッシュ値から「salt(頭2バイト分)」を抽出して、対象パスワードをその「抽出salt」で「crypt」して比較することになるかと思います。
「salt」を固定化すればDBへの直検索が可能になり、たいへん効率的なのですがそのようにしてはいかがでしょうか?
また、「salt」は先頭2バイトしか処理対照になりませんので、長いコードを生成しても無駄になります。 蛇足ですが質問サンプルでは実際に動かすと先頭2文字は必ず'$1'となりますので・・・
ご参考までに

## 塩の生成
srand();
my @salt = ( "A".."Z", "a".."z", "0".."9", ".", "/" );
my $salt = '$1$' . join('', map($salt[int(rand(64))], 1..8)) . '$';

print $salt;
print "\n";

## パスワード「TESTTEST」で実験
my $pass = crypt("TESTTEST", $salt);
print $pass;
print "\n";

## エンコードされた文字から塩を取り出し
$pass =~ m/(^..)*/;
my $new_salt = $1;

print $new_salt;
print "\n";

## その取り出した塩でもう一回エンコード
my $new_pass = crypt("TESTTEST", $new_salt);
print $new_pass;
print "\n";

この回答への補足

ご教授頂きまして有難うございます。
お教え頂いたソースを参考にさせて頂いたのですが、少し私では理解できなくてお恥ずかしいのですが、まだ解決に至りませんでした。

## 塩の生成
srand();
@salt = ( "A".."Z", "a".."z", "0".."9", ".", "/" );
$salt = '$1$' . join('', map($salt[int(rand(64))], 1..8)) . '$';

$pass = crypt("$in{'pass'}", $salt);

#html表示
print <<"EOM";
<form>
名前 <input type="text" name="name"><br>
パスワード <input type="password" name="pass">
</form>
EOM

## エンコードされた文字から塩を取り出し
$pass =~ m/(^..)*/;
$new_salt = $1;

## その取り出した塩でもう一回エンコード
$new_pass = crypt("$in{'pass'}", $new_salt);

if (crypt($new_pass,$ary) eq "$ary") {
$flag = '0'; #認証OK
}

大まかにですが、上記のような感じにしたのですが、とんちんかんな事を記述していたら申し訳ございません。
何か根本的に間違っているのでしょうか?
何度も申し訳ございませんが、ご教授頂けますと幸いです。

補足日時:2006/09/15 06:20
    • good
    • 0

そういう場合は、PerlからDBIを使い、sqlを発行したほうがいいです。


入力されたパスワードをMD5でselectします。

$sql = "select * from table where pass = MD5('" .$in{'pass'} ."')";

この回答への補足

ご教授頂きまして有難うございます

現在DBに関する記述の中で、

$sth = $dbh->prepare("SELECT name,pass FROM テーブル名");#DBの中の#nameとpassがほしい

上記に、

$sth = $dbh->prepare("SELECT name,pass FROM テーブル名 where pass = MD5('" .$in{'pass'} ."')");

このように記述すればよいのでしょうか?
ただ、これではうまく動作をすることができず、少し私では理解できなくてお恥ずかしい限りです。

何度も申し訳ございませんが、具体的な記述方法などをお教えいただけますと幸いです。

補足日時:2006/09/15 06:27
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!