0

I'm making a website that users can log in and new members can sign in, but when I go and test the site and go to the new member button to register, it gives me a warning saying that the password has to be between 6 and 12 characters even when I do put a password in that is in between those parameters. The code that I'm using is

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
  // include function files for this application
  require_once('bookmark_fns.php');

  //create short variable names
  $email=$_POST['email'];
  $username=$_POST['username'];
  $passwd=$_POST['passwd'];
  $passwd2=$_POST['passwd2'];
  // start session which may be needed later
  // start it now because it must go before headers
  session_start();
  try   {
    // check forms filled in
    if (!filled_out($_POST)) {
      throw new Exception('You have not filled the form out correctly. Please go back and try again.');
    }

    // email address not valid
    if (!valid_email($email)) {
      throw new Exception('That is not a valid email address.  Please go back and try again.');
    }

    // passwords not the same
    if ($passwd != $passwd2) {
      throw new Exception('The passwords you entered do not match. Please go back and try again.');
    }

    // check password length is ok
    // ok if username truncates, but passwords will get
    // munged if they are too long.
    if (!preg_match('/^(?=.*\d)(?=.*[A-Za-z])[0-9A-Za-z]{6,12}$/', $passwd)) {
        throw new Exception('Your password must be between 6 and 12 characters inclusive. Please go back and try again.');
    }

    // attempt to register
    // this function can also throw an exception
    register($username, $email, $passwd);
    // register session variable
    $_SESSION['valid_user'] = $username;

    // provide link to members page
    do_html_header('Registration successful');
    echo "Welcome " . $_POST["username"];
    echo 'Your registration was successful.  Go to the members page to start setting up your bookmarks!';
    do_html_url('member.php', 'Go to members page');

   // end page
   do_html_footer();
  }
  catch (Exception $e) {
     do_html_header('Warning:');
     echo $e->getMessage();
     do_html_footer();
     exit;
  }
?>

I want the page to be able to display the person's name when they've registered correctly or display an error message saying that they need to enter a password between 6 to 12 characters and being inclusive or if they've not entered an email or name.

EDIT

Since changing the line 34 from 8,12 to 6,12 I have now got Warning: mysqli::mysqli(): (HY000/2002): No such file or directory in the file shown

<?php

function db_connect() {
   $result = new mysqli('localhost', 'bm_user', 'password', 'bookmarks');
   if (!$result) {
     throw new Exception('Could not connect to database server');
   } else {
     return $result;
   }
}

?>

And Warning: mysqli::query(): Couldn't fetch mysqli in the file

require_once('db_fns.php');

function register($username, $email, $password) {
// register new person with db
// return true or error message

  // connect to db
  $conn = db_connect();

  // check if username is unique
  $result = $conn->query("select * from user where username='".$username."'");
  if (!$result) {
    throw new Exception('Could not execute query');
  }

  if ($result->num_rows>0) {
    throw new Exception('That username is taken - go back and choose another one.');
  }

  // if ok, put in db
  $result = $conn->query("insert into user values
                     ('".$username."', sha1('".$password."'), '".$email."')");
  if (!$result) {
      throw new Exception('Could not register you in database - please try again later.');
  }

  return true;
}

function login($username, $password) {
// check username and password with db
// if yes, return true
// else throw exception

  // connect to db
  $conn = db_connect();

  // check if username is unique
  $result = $conn->query("select * from user
                     where username='".$username."'
                     and passwd = sha1('".$password."')");
  if (!$result) {
      throw new Exception('Could not log you in.');
  }

  if ($result->num_rows>0) {
      return true;
  } else {
     throw new Exception('Could not log you in.');
  }
}

function check_valid_user() {
// see if somebody is logged in and notify them if not
  if (isset($_SESSION['valid_user']))  {
      echo "Logged in as ".$_SESSION['valid_user'].".<br />";
  } else {
     // they are not logged in
     do_html_heading('Warning:');
     echo 'You have not filled the form out correctly.
          Please go back and try again.<br />';
     do_html_url('login.php', 'Login');
     do_html_footer();
     exit;
  }
}

function change_password($username, $old_password, $new_password) {
// change password for username/old_password to new_password
// return true or false

  // if the old password is right
  // change their password to new_password and return true
  // else throw an exception
  login($username, $old_password);
  $conn = db_connect();
  $result = $conn->query("update user
                      set passwd = sha1('".$new_password."')
                      where username = '".$username."'");
  if (!$result) {
    throw new Exception('Password could not be changed.');
  } else {
    return true;  // changed successfully
  }
}

function get_random_word($min_length, $max_length) {
// grab a random word from dictionary between the two lengths
// and return it

  // generate a random word
  $word = '';
  // remember to change this path to suit your system
  $dictionary = '/usr/dict/words';  // the ispell dictionary
  $fp = @fopen($dictionary, 'r');
  if(!$fp) {
    return false;
  }
  $size = filesize($dictionary);

  // go to a random location in dictionary
  $rand_location = rand(0, $size);
  fseek($fp, $rand_location);

  // get the next whole word of the right length in the file
  while ((strlen($word) < $min_length) || (strlen($word)>$max_length) || (strstr($word, "'"))) {
     if (feof($fp)) {
        fseek($fp, 0);        // if at end, go to start
     }
     $word = fgets($fp, 80);  // skip first word as it could be partial
     $word = fgets($fp, 80);  // the potential password
  }
  $word = trim($word); // trim the trailing \n from fgets
  return $word;
}

function reset_password($username) {
// set password for username to a random value
// return the new password or false on failure
  // get a random dictionary word b/w 6 and 13 chars in length
  $new_password = get_random_word(6, 13);

   if($new_password == false) {
    throw new Exception('Could not generate new password.');
  }

  // add a number  between 0 and 999 to it
  // to make it a slightly better password
  $rand_number = rand(0, 999);
  $new_password .= $rand_number;

  // set user's password to this in database or return false
  $conn = db_connect();
  $result = $conn->query("update user
                      set passwd = sha1('".$new_password."')
                      where username = '".$username."'");
  if (!$result) {
    throw new Exception('Could not change password.');  // not changed
  } else {
    return $new_password;  // changed successfully
  }
}

function notify_password($username, $password) {
// notify the user that their password has been changed

$conn = db_connect();
$result = $conn->query("select email from user
                        where username='".$username."'");
if (!$result) {
  throw new Exception('Could not find email address.');
} else if ($result->num_rows == 0) {
  throw new Exception('Could not find email address.');
  // username not in db
} else {
  $row = $result->fetch_object();
  $email = $row->email;
  $from = "From: support@phpbookmark \r\n";
  $mesg = "Your PHPBookmark password has been changed to ".$password."\r\n"
          ."Please change it next time you log in.\r\n";

      if (mail($email, 'PHPBookmark login information', $mesg, $from)) {
        return true;
      } else {
        throw new Exception('Could not send email.');
      }
    }
}

?>
  • 4
    Allow users to use the [passwords / phrases](https://xkcd.com/936/) they desire. [Don't limit passwords.](http://jayblanchard.net/security_fail_passwords.html) and [use the proper methods to hash and verify passwords with PHP](http://jayblanchard.net/proper_password_hashing_with_PHP.html). Make sure that you [don't escape passwords](http://stackoverflow.com/q/36628418/1011527) or use any other cleansing mechanism on them before hashing. Doing so *changes* the password and causes unnecessary additional coding. – Jay Blanchard Apr 18 '16 at 17:25
  • 2
    ^- what he said. To answer your question your regex checks for a length between 8 and 12, not 6 and 12. – JimL Apr 18 '16 at 17:26
  • 2
    @JayBlanchard actually, having a maximum length is a good thing, but that maximum should be high, like 1024 characters or more. Current hashing algorithms are purposely slow. Sending over large passwords is a simple way to tie the server up via DoS through a known "slow" page. http://arstechnica.com/security/2013/09/long-passwords-are-good-but-too-much-length-can-be-bad-for-security/ – Jonathan Kuhn Apr 18 '16 at 17:35
  • Thanks for the info @JonathanKuhn! – Jay Blanchard Apr 18 '16 at 17:40
  • @JonathanKuhn ran som benchmarks and I don't think this applies to Bcrypt. It would make sense as it has a built in max length of 72 bytes. Having a (high) upper limit would be good anyway though as the PASSWORD_DEFAULT algorithm might change. Just thought it was worth mentioning as the article covers pbkdf2 – JimL Apr 18 '16 at 17:45
  • @JayBlanchard I'm not sure I agree with not limiting passwords *at all*. As you said in your article users "don't create strong passwords, they use the word 'password' as their password more often than not". If I don't care if the user's account is hacked I'll let them choose whatever password they want, but if I'm doing anything where it would really matter, I will take whatever precautions I can to prevent their account from being hacked. If that means forcing them to use upper case, numbers and/or symbols, that seems like good practice to me. – Mike Apr 18 '16 at 17:48
  • 1
    @Mike the irony is that enforcing a spesific set of rules actually limits how random the passwords are. I'd rather add 2fa, like google authenticator into the mix. – JimL Apr 18 '16 at 17:52
  • @JimL Most people don't choose "random" passwords, so I don't think that matters at all. And I would agree 2FA is much better. I have implemented it myself in one of my apps. – Mike Apr 18 '16 at 17:56
  • 1
    @Mike I believe it is our job to guide them but not limit them. It is my belief that we should educate, not adjudicate and given all of the reporting concerning hacked accounts I would *hope* that online users are becoming more savvy to protecting their information. I always place a recommendation about using passphrases on any account sign-up I create or modify. – Jay Blanchard Apr 18 '16 at 17:56
  • @OP, for the new issue, that is unrelated to the original question and should be a separate post. However, just google the error. There are tons of responses that come up on how to solve it like [this one](http://stackoverflow.com/questions/20073168/my-database-user-exists-but-i-still-get-an-hy000-2002-no-such-file-or-direct). – Jonathan Kuhn Apr 18 '16 at 17:59
  • @JayBlanchard I think it's wishful thinking to expect all your users to choose strong passwords, no matter how much education you throw at them. – Mike Apr 18 '16 at 17:59
  • No doubt @Mike, you're very right. – Jay Blanchard Apr 18 '16 at 18:00
  • For your additional *warning* message, try changing `localhost` to your IP (`127.0.0.1`) in your connection: `$result = new mysqli('localhost', 'bm_user', 'password', 'bookmarks');` to `$result = new mysqli('127.0.0.1', 'bm_user', 'password', 'bookmarks');` – mferly Apr 18 '16 at 18:05
  • 1
    @JonathanKuhn To add to JimL's tests, I also tried it with scrypt and to hash an 8 character password took 0.31 seconds to hash 5 million random bytes took 0.42 sec to compute using `$N = pow(2,14); $r = 8; $p = 8;`. So to have any significant effect you're going to have to send massive passwords. Then again, if the server has low memory DDoSing with even small passwords would take it to its knees if the parameters chosen require too much memory to calculate. I could see this having a much larger effect than the password length. – Mike Apr 18 '16 at 18:18

1 Answers1

0

Your regex is off. You want 6-12 characters, but your regex is accomodating 8-12:

{8,12}

Change to:

{6,12}

But as was pointed out in the comments, there is no reason you should be messing with a user's password, offering (forcing) restrictions like that. And to be perfectly honest, when (and it's been a long time since) I come across a site that restricts what I can use as a password, I simply don't register.

mferly
  • 1,586
  • 1
  • 11
  • 18