4

現在、セッションを使用してユーザーをサイトにログインさせています。ここで、クッキーをミックスに追加して、ユーザーが数日後にサイトにアクセスできるようにし、再度ログインする必要がないようにしたいと考えています。

パスワードを Cookie に保存したり、何かを暗号化したりしたくないので、私の解決策は、ユーザー名を Cookie に保存し、一種のログイン ハッシュ (各ユーザーの各ログインに固有) を使用して別の Cookie を作成することです。次に、各ページの上部で、Cookie とログイン セッションを確認します。Cookie は存在するがセッションが存在しない場合は、ユーザー名を見つけてユーザーをログインさせます。

したがって、これは、ログインに成功した後に発生します ($row['username']は入力したユーザー名です)。

$_SESSION['username']=$row[username];
$_SESSION['user_id']=$row['id'];
$loginhash = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 32);
$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, "/" ) ;

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

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

そして、各ページの上部で、次のようにします。

if($_COOKIE['userlogin'] && !isset($_SESSION[user_id])){
    $username=mysql_real_escape_string($_COOKIE['userlogin']);
    $loginhash=mysql_real_escape_string($_COOKIE['loginhash']);
    $result=mysql_query("select * from members where (username='$username' || email='$username') && loginhash='$loginhash' ") or die (mysql_error());
    $row=mysql_fetch_array($result);
    $_SESSION['username']=$row[username];
    $_SESSION['user_id']=$row['id'];
}

そしてもちろん、ユーザーが手動でログアウトするときに Cookie の設定を解除します。

私の質問は、これを行うのは安全なことですか (他の誰かがユーザーのコンピューターを使用する危険は別として) ですか? ログインごとにランダム ハッシュが生成されるため、誰かが誰かのユーザー名で Cookie を作成し、その人としてログインすることはできません。

ログイン スクリプトは HTTPS 上にあるため、その側に危険はありません。

4

2 に答える 2

6

いいえ、これは安全ではありません。

あなたがこれを行っている方法には、2つの大きな問題があります。

  1. データベースにパスワードを保存しない理由は、データベースが侵害された場合に、攻撃者がサーバー上のアカウントにアクセスできないようにするためです...しかし、これはまさにあなたがloginhash. 私があなたのデータベースを侵害した場合、データベースusernameからおよびを使用して Cookie を作成するだけで、次の 14 日間、アクティブな Cookie を持つ任意のユーザーとしてログインできloginhashます。

    これを修正するには、ランダム キーを生成し、それを Cookie に保存してから、ハッシュ関数を使用して実行しbcrypt、ダイジェストをデータベースに保存します。このように、データベースの完全なダンプがあっても、ユーザーは他のユーザーとしてサイトに単純にログインすることはできません。もちろん、生ではなくダイジェストを比較するように比較演算子を変更する必要があります。

  2. str_shuffle関数は暗号的に安全ではありません。これはかなり予測可能な内部で使用されrand、このハッシュはパスワードよりもはるかに簡単な攻撃ベクトルになります. 代わりに、OS でランダム エントロピーを使用します (URANDOM は Unblocking Random を指します。RANDOM ほど安全ではありませんが、システムが多くの処理を実行し、エントロピーを生成するため、それで十分です)。

このパスワードリセットクラスから適応:

function generateRandomBase64String($length = 32)
{
  if (!defined('MCRYPT_DEV_URANDOM')) die('The MCRYPT_DEV_URANDOM source is required (PHP 5.3).');
  $binaryLength = (int)($length * 3 / 4 + 1);
  $randomBinaryString = mcrypt_create_iv($binaryLength, MCRYPT_DEV_URANDOM);
  $randomBase64String = base64_encode($randomBinaryString);
  return substr($randomBase64String, 0, $length);
}

ここで、Cookie ジャッキングをより困難にする必要があります。

この記事では、ユーザーが Cookie を使用する代わりに認証情報を使用してログインするたびに、Drupal がログイン トークンを処理しusernameloginhashを保存する方法について説明します。とseries_idは、前述のランダム関数を使用して生成できます。loginhashseries_id

ユーザーがログインすると、データベースがチェックされます。とがすべて存在する場合、ユーザーはログインし、新しいusernameCookie同じと新しいで生成されます。つまり、各 Cookie は 1 回しか使用できません。loginhashseries_idusernameseries_idloginhash

さらに、この方法でログインしたユーザーは、「適切な」パスワード ログインを行わずに、パスワードのリセットの要求、資金の引き出し、機密情報の閲覧などの危険な機能を実行することはできません。これは、Cookie がジャックされたユーザーを保護するためです。

series_idが存在するが が一致しないログインが検出された場合、loginhashこのユーザーの有効な Cookie をすべて消去し、アカウントへのアクセスに無効な Cookie が使用されたことを示す強い言葉のメッセージを残します。

余談ですが remysql_*関数

これは新しいコードのようで、まだ展開されていません。引き返すのに遅すぎない場合は、データベース ドライバーをmysqli(ドキュメント) に切り替えることを検討してください。これは、 と非常によく似た手順スタイルを維持しmysqlますが、バインドされたパラメーターやその他の最新の関数を使用してデータ セキュリティを向上させることができます。

于 2013-08-19T14:42:20.130 に答える
1

改善すべき点がいくつかあります。

  1. まず、オペレーティング システムのランダム ソース (URANDOM) を使用してログイン トークンを生成することをお勧めします。コードは各文字を 1 回だけ使用し、シャッフル関数はおそらく現在の時刻 (乱数) に基づいています。したがって、おおよそのログイン時間を知っていると、可能な組み合わせをひどく絞り込むことになります。

  2. トークンはプレーンテキストでデータベースに保存しないでください。代わりに、トークンのハッシュのみをデータベースに保存する必要があります。誰かがあなたのデータベース (SQL インジェクション) を読み取ることができたとしても、その人はまだコードを使用できません。

  3. この関数setcookie()には と の 2 つのパラメーターが$secureあり$httponly、両方を true に設定する必要があります。そうしないと、ブラウザーがだまされて、暗号化されていないトークンが HTTP ページに送信される可能性があります (画像要求にも送信されます)。

于 2013-08-19T14:46:24.600 に答える