- 締切済み
DB内にMD5でハッシュ化されたパスワードとの照合
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に関して殆ど解っていないもので、とんちんかんな記述かもしれませんが、ご教授いただけますと幸いです。 宜しくお願いいたします。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- ralf124c
- ベストアンサー率52% (232/446)
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の処理によって先頭の半角スペースが無視されますが、本体への「インデント」は忘れないようにしてください。
- ralf124c
- ベストアンサー率52% (232/446)
この質問サンプルから想像した場合は、「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";
- moon_night
- ベストアンサー率32% (598/1831)
そういう場合は、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'} ."')"); このように記述すればよいのでしょうか? ただ、これではうまく動作をすることができず、少し私では理解できなくてお恥ずかしい限りです。 何度も申し訳ございませんが、具体的な記述方法などをお教えいただけますと幸いです。
補足
ご教授頂きまして有難うございます。 お教え頂いたソースを参考にさせて頂いたのですが、少し私では理解できなくてお恥ずかしいのですが、まだ解決に至りませんでした。 ## 塩の生成 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 } 大まかにですが、上記のような感じにしたのですが、とんちんかんな事を記述していたら申し訳ございません。 何か根本的に間違っているのでしょうか? 何度も申し訳ございませんが、ご教授頂けますと幸いです。