1

私が開発しているウェブサイト用の簡単なパスワード回復機能を書いていますが、有効期限について疑問に思っていました。

要点を言えば、送信するパスワードのリセットリンクに約48時間の有効期限を追加したいと思います。現在の時刻を保存するために新しい列を作成し、しばらくしてからそれがまだ有効かどうかを確認する必要がありますか、それとももっと簡単な方法がありますか?

これが私のコードです。

public function forgotPass($email) {
    $bd = new Bd();
    $conn = $bd->connect();
    $stt = $conn->prepare("SELECT * FROM Users where email=?");
    $stt-> bind_param("s",$email);
    $stt-> execute();
    $result = $stt->get_result();
    if (mysqli_num_rows($result) == 1) {
        $stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
        $recovery = $this->randHash(8);

        if (!$recovery)
            return false;

        $stt-> bind_param("s",$recovery);
        $stt-> execute();
    }
}

これが私のrandHashコードです:

private static function randHash($lenght) {
    if (!filter_var($lenght, FILTER_VALIDATE_INT)) {
        return false;
    }   
    $allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $max = strlen($allowed) - 1;
    for ($i=1;$i<=$lenght;$i++) {
        $hash .= $allowed[mt_rand(0, $max)];
    }
    return $hash;
}
4

3 に答える 3

3

データベースにリセットトークンを使用して有効期限を保存するだけです。期限が切れたら、リセットトークンを受け入れないでください。これは、これまでで最も簡単で安全な方法です。

もう1つの方法は、リセットハッシュを作成し、時間を追加し、それを秘密鍵で暗号化することです。ハッシュをチェックするときに、タイムスタンプを復号化してチェックします。ただし、キーが漏洩した場合、この方法はURLにプレーンテキストで入力するのと同じくらい弱くなります。

于 2012-12-06T12:52:04.443 に答える
0

現在の日付をデータベースに保存することは、1つの方法です。その後、48時間未満のオフかどうかを簡単に確認できます。もう1つの方法は、メールに時間を含めることです。

public function forgotPass($email) {
    $bd = new Bd();
    $conn = $bd->connect();
    $stt = $conn->prepare("SELECT * FROM Users where email=?");
    $stt-> bind_param("s",$email);
    $stt-> execute();
    $result = $stt->get_result();
    if (mysqli_num_rows($result) == 1) {
        $hash1 = md5(microtime().$email.'xx'); //create a unique number for email
        $ctime = time();
        $hash2 = md5($hash1.$ctime); //create a unique hash based on hash1 and time

        $stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
        $recovery = $hash2;

        if (!$recovery)
            return false;

        $stt-> bind_param("s",$recovery);
        $stt-> execute();

        //send email with link
        // http://www.example.com/resetpass.php?hash=$hash1&time=$ctime
    }
}

//and then in resetpass.php
//NEEDS CHECKS FOR VALID QUERYVALUES

if (time()-$_GET['time'] <= 48 * 60 * 60)  {
  $checkhash = md5($_GET['hash'].$_GET['time']);
  //check database for hash
}
于 2012-12-06T12:54:43.863 に答える
0

編集:私は今朝、この回答に関する電子メールを受け取り、ハッシュ部分が本当に一意のIDを作成するためだけのものであるかどうかを尋ねました。以下は私の応答です:

Stack Overflowの質問に目を通し、読み直しました。このコードは、本当に一意のIDを作成するためだけのものではありません(ただし、衝突がないことが重要です)。また、他の誰かがユーザーアカウントにアクセスするために独自のパスワード回復リンクを作成することを非常に困難にすることでもあります。

ユーザー名と電子メールを使用して(コード全体をハッシュせずに)ハッシュを作成することで、ユーザーのIDに追加の検証を含めることができます。つまり、リンクを持っているだけでは十分ではありません。パスワードをリセットするには、有効なユーザー名と電子メールアドレスの組み合わせも必要です。

レインボーテーブルを倒すための基本的な試みとして、ユーザー名、現在の時刻、および電子メールの前に文字列が付加されます。振り返ってみると、 ""ソルトをそれぞれbase64_encode($ row ['username'])とbase64_encode($ email)に置き換える方がよいでしょう。


Recoveryとrecovery_expiryの2つの列を作成することをお勧めします。Recovery_expiryはリンクの有効期限が切れたときに保持され、recoveryは比較する必要のあるハッシュを保持します。これは、ユーザー名、現在の時刻が追加されたソルト、およびユーザーの現在の電子メールアドレスで構成されます。

function forgotPass($email)
{
    $currTime = time();
    $expiryTime = 60 * 60 * 24 * 2; // Two days

    $bd = new Bd();
    $conn = $bd->connect();
    $stt = $conn->prepare("SELECT * FROM Users where email=?");
    $stt->bind_param("s", $email);
    $stt->execute();
    $result = $stt->get_result();
    if (mysqli_num_rows($result) == 1)
    {
        $row = mysqli_fetch_array();
        $stt = $conn->prepare("INSERT INTO Users(recovery, recovery_expiry)"
               . " VALUES(?,?)");
        $hash = hash("sha256", " " . $row['username'])
                . hash("sha256", "vivid" . $currTime)
                . hash("sha256", " " . $email);

        $stt->bind_param("s", $hash);
        $stt->bind_param("i", $currTime + $expiryTime);
        $stt->execute();
    }
    else
    {
        // Return that the given email address did not match any records
    }
    // Here would be the logic to send the forgotten password link to the user
}

function checkHash($hash)
{
    $row = null;
    $currTime = time();
    $bd = new Bd();
    $conn = $bd->connect();
    $stt = $conn->prepare("SELECT * FROM Users WHERE recovery=? AND recovery_expiry < $currTime");
    $stt->bind_param("s", $hash);
    $stt->execute();
    $result = $stt->get_result();
    if (mysqli_num_rows($result) == 1)
    {
        $row = mysqli_fetch_array();
    }
    return $row;
}
于 2012-12-06T13:41:04.620 に答える