4

私はかなり標準的な Cookie ログイン方法を使用しています。ユーザーに 2 つの Cookie を与えます。1 つはユーザー名で、もう 1 つはランダムに生成された文字列とユーザー固有のソルトです。

これは、ログイン時に何が起こるかです:

$_SESSION['username']=$row[username];
$_SESSION['user_id']=$row['id'];
$loginhash=generateRandomBase64String()."_".$row['salt'];
$number_of_days = 14;
$date_of_expiry = time() + 60 * 60 * 24 * $number_of_days ;
setcookie( "userlogin", $row['username'], $date_of_expiry, "/" ) ;
setcookie( "loginhash", $loginhash, $date_of_expiry, "/" ) ;
$cryptedhash=crypt($loginhash);

$today=date("Y-m-d");

mysql_query("update members set last_login='$today',loginhash='$cryptedhash' where id='$row[id]' ") or die(mysql_error());

したがって、$loginhash値は次のようなものPe0vFou8qe++CqhcJgFtRmoAldpuIs+d_g5oijF76で、その暗号化されたバージョンがデータベースに保存されます。ソルトは、サインアップ時に各ユーザーに対して生成されるため、データベースに既に存在します。

セッション変数 ( $_SESSION[username]) を使用して、ユーザーのログイン状態を維持します。次に、ユーザーがサイトにアクセスしたときに、次の 2 つのことを確認します。$_SESSION[username]が設定されていない場合は$_COOKIE[userlogin]、ユーザーがログインできるようにハッシュが正しいかどうかを確認します。問題は、ハッシュが決して正しくないことです。

if($_COOKIE['userlogin'] && !isset($_SESSION[user_id])){
    $username=mysql_real_escape_string($_COOKIE['userlogin']);
    $loginhash=mysql_real_escape_string($_COOKIE['loginhash']);
    $salt=substr($loginhash,-8);
    $result=mysql_query("select * from members where (username='$username' || email='$username') && salt='$salt' limit 1 ") or die (mysql_error());
    $row=mysql_fetch_assoc($result);
    $cryptedhash=$row['loginhash'];
    if (crypt($loginhash, $cryptedhash) == $cryptedhash){
        $_SESSION['username']=$row[username];
        $_SESSION['user_id']=$row['id'];
    }
}

$_COOKIE[userlogin]が正しい値です。データベースでユーザー名とソルトの組み合わせを確認すると、正しい結果が見つかりました(echo $row[username]正しい値が得られます)。ただし、それif以下の条件は決して満たされません。PHP の構成に何か奇妙な点があると思いますが、同じ暗号化メカニズムを使用してパスワードを保存すると、正常に動作します。

では、ここで何が問題なのか誰にもわかりますか?

PS ここで、Cookie の安全性や利用可能なさまざまなハッシュ関数についての議論を始めるつもりはありません。

4

3 に答える 3

3

問題は次のとおりです。

crypt() への最初の呼び出しでは、salt を指定しません。crypt() への 2 回目の呼び出しでは、$cryptedhash をソルトとして渡します。

crypt()提供しない場合はランダムなソルトを生成し、返されたハッシュにそのソルトを追加することが文書化されています。これには、返されたソルト + ハッシュを後続の呼び出しのハッシュとして渡すと、crypt() が正しいソルトを引き出すという副作用があります。

残念ながら、使用されるアルゴリズムとソルト + ハッシュの長さ/形式は、オペレーティング システム、PHP バージョン、およびソルト パラメータを指定したかどうかの組み合わせに基づいています。以前にコードを使用したとき、crypt() への両方の呼び出しで DES が選択されたという嬉しい偶然がありました。現在、あなたの環境は crypt() への 2 つの呼び出しに異なるアルゴリズムを使用しています。これは、そのうちの 1 つのみでハッシュを指定したためです。

解決策は、crypt() への両方の呼び出しに一貫したソルトを渡すことです。ハッシュしたい文字列にソルトを追加するのをやめて、実際にユーザーソルトをソルトパラメーターとして渡すと、すべてうまくいきます。

于 2013-08-27T15:20:47.367 に答える
0

この行は間違ってい$loginhash=mysql_real_escape_string($_COOKIE['loginhash']);ます。エスケープする必要はありません (データベースで使用していません)。crypt() に渡すときは変更せずに使用する必要があるため、この行は次のように記述できます$loginhash=$_COOKIE['loginhash'];(少なくともコード)

于 2013-08-27T13:37:23.203 に答える