草庐IT

php - 忘记密码电子邮件重置 php 工作,除了原始密码和更改密码都不允许登录

coder 2023-10-26 原文

我为我的登录系统创建了一个忘记密码更改 php 函数,它向忘记密码的用户发送一封电子邮件,并提供一个使用散列 token 的链接以更改他们的密码。一旦用户选择了电子邮件链接,他们就可以更改密码,然后用新的散列密码更新 mysql。

在我尝试使用新密码登录之前,代码的各个方面似乎都能正常工作。我收到回显“用户名/密码组合不正确”(在 LOGIN.PHP 页面上找到)。尝试原始密码也会在 LOGIN.PHP 页面上回显相同的错误。

不确定为什么我的 sql 查询没有将更新后的密码与现有用户名匹配并允许登录?

为了便于通过代码进行解析,我排除了我认为不是问题的部分。我包含了 5 个 php 文件。

忘记密码.PHP

<?php
if (!isset($_GET['email'])) {
    echo '<form action="">//Form for password reset here</form>';
    exit();
}


define('DB_USER', '');
define('DB_PASS', '');
define('DB_NAME', '');

$email = $_GET['email'];

function connect()
{
//Connect to db
}
connect();

$q = "SELECT email FROM users WHERE LCASE(TRIM(email))='" . strtolower(trim($email)) . "'";
$r = mysql_query($q);
$n = mysql_num_rows($r);

if ($n == 0) {
    echo "Email id is not registered";
    die();

}

//token updated into sql db for user
    $token=getRandomString(10);
    $q="UPDATE users SET token=('".$token."') WHERE email=('".$email."')";
    mysql_query($q);

function getRandomString($length) 
   {

//token created
}
//email creation code here

重置.PHP

<?php
session_start();

//Define db connection parameters

    $token=$_GET['token'];

function connect() {

//Connection to db executed
    }

connect();

if(!isset($_POST['password'])){
    $q="SELECT email FROM users WHERE token='".$token."' and used='0'";
    $r=mysql_query($q);
    while($row=mysql_fetch_array($r))
   {

$email=$row['email'];
   }

If ($email!=''){
      $_SESSION['email']=$email;
}

    else die("Invalid link or Password already changed");}

$password=$_POST['password'];
$email=$_SESSION['email'];

if(!isset($password)){

echo '
//Change password form
';}

if(isset($_POST['password'])&&isset($_SESSION['email']))
{

//Update sql db with newly created password
$q="UPDATE users SET password='".md5($password)."' WHERE email='".$email."'";
$r=mysql_query($q);

if($r)mysql_query("UPDATE users SET used='1' WHERE token='".$token."'");echo "Your password is changed successfully";
if(!$r)echo "An error occurred";
}
?>

LOGIN.PHP(显示错误消息)

<div id="loginContainer">
<div id="loginMessage">
        <?php if ( $logged == 'invalid' ) : ?>
            <p class="name_pass">
                The username/password combination is incorrect. Try again.
            </p>
        <?php endif; ?>
        <?php if ( $_GET['reg'] == 'true' ) : ?>
            <p class="success">Your registration was successful, please login below.
            </p>
        <?php endif; ?>
        <?php if ( $_GET['action'] == 'logout' ) : ?>
            <?php if ( $loggedout == true ) : ?>
                <p class="log_out">You have been successfully logged out.
                </p>
            <?php else: ?>
                <p class="problem">There was a problem logging you out.
                </p>
            <?php endif; ?>
        <?php endif; ?>
        <?php if ( $_GET['msg'] == 'login' ) : ?>
            <p class="must_login">You must login to view this content. Please login below.
                </p>
        <?php endif; ?>
</div>

CLASS.PHP(登录函数)

        function login($redirect) {
        global $jdb;

        if ( !empty ( $_POST ) ) {


            $values = $jdb->clean($_POST);


            $subname = $values['username'];
            $subpass = $values['password'];


            $table = 'users';


            $sql = "SELECT * FROM $table WHERE username = '" . $subname . "'";
            $results = $jdb->select($sql);


            if (!$results) {
                die('Sorry, that username does not exist!');
            }


            $results = mysql_fetch_assoc( $results );


            $storeg = $results['date'];


            $stopass = $results['password'];


            $nonce = md5('registration-' . $subname . $storeg . NONCE_SALT);


            $subpass = $jdb->hash_password($subpass, $nonce);


            if ( $subpass == $stopass ) {


                $authnonce = md5('cookie-' . $subname . $storeg . AUTH_SALT);
                $authID = $jdb->hash_password($subpass, $authnonce);


                setcookie('logauth[user]', $subname, 0, '', '', '', true);
                setcookie('logauth[authID]', $authID, 0, '', '', '', true);


                $url = "http" . ((!empty($_SERVER['HTTPS'])) ? "s" : "") . "://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
                $redirect = str_replace('login.php', $redirect, $url);


                header("Location: $redirect");
                exit;   
            } else {
                return 'invalid';
            }
        } else {
            return 'empty';
        }
    }

INDEX.PHP(登录成功后的登陆页面)

<?php
require_once('load.php');
$logged = $j->checkLogin();

if ( $logged == false ) {
    //Build our redirect
    $url = "http" . ((!empty($_SERVER['HTTPS'])) ? "s" : "") . "://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
    $redirect = str_replace('index.php', 'login.php', $url);

    //Redirect to the home page
    header("Location: $redirect?msg=login");
    exit;
} else {
    //Grab our authorization cookie array
    $cookie = $_COOKIE['logauth'];

    //Set our user and authID variables
    $user = $cookie['user'];
    $authID = $cookie['authID'];

    //Query the database for the selected user
    $table = 'users';
    $sql = "SELECT * FROM $table WHERE username = '" . $user . "'";
    $results = $jdb->select($sql);

    //Kill the script if the submitted username doesn't exit
    if (!$results) {
        die('Sorry, that username does not exist!');
    }

    //Fetch our results into an associative array
    $results = mysql_fetch_assoc( $results );
?>

感谢您提供的所有帮助。我感谢任何愿意看一下代码来帮助我弄清楚登录过程的最后一部分的人。 谢谢。

最佳答案

在您的 reset.php 文件中,您存储了密码的未加盐 MD5...

$password=$_POST['password'];
$q="UPDATE users SET password='".md5($password)."' WHERE email='".$email."'";

...但随后您将它与不同的东西进行比较...

$subpass = $values['password']; // seems to be the entered password
...
$stopass = $results['password']; // seems to be the stored MD5 password hash
...
$subpass = $jdb->hash_password($subpass, $nonce); // probably not an unsalted MD5
if ( $subpass == $stopass ) // comparison of different things

即使您让这段代码工作,这也是一个非常不安全的解决方案。相反,您绝对应该切换到 PHP 中内置的密码哈希函数。 DB 字段应为 varchar(255),代码可能如下所示:

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($_POST['password'], PASSWORD_DEFAULT);
$q="UPDATE users SET password='".$hashToStoreInDb."' WHERE email='".$email."'";

要检查密码,您需要从数据库中获取哈希并将其与 password_verify 进行比较,因此比较将使用与存储哈希相同的盐来完成。

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $stopass.
$subpass = $values['password'];
...
$stopass = $results['password'];
...
$isPasswordCorrect = password_verify($subpass, $stopass);
if ($isPasswordCorrect)

您代码中的另一个问题是 SQL 注入(inject),您可以通过使用准备好的语句来避免此漏洞。您可以在另一个 answer 中找到 MySqli 或 PDO 的示例.

关于php - 忘记密码电子邮件重置 php 工作,除了原始密码和更改密码都不允许登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43566558/

有关php - 忘记密码电子邮件重置 php 工作,除了原始密码和更改密码都不允许登录的更多相关文章

  1. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  5. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  6. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  7. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  8. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  9. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  10. ruby - 更改 ActiveRecord 中对象的类 - 2

    假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

随机推荐