3

I'm working on a website and I would like to allow users to be able to login to the site. I'm a self taught developer so I'm not exactly sure what the best practices are. I've used bcrypt before in my java applications and have implemented it below in the password php file below (only real important lines there are at the end after the class).

My only concern right now with the login system so far is that the ajax I used is visible and shows what script is running for checking the password. Is this still all secure? If not how should this be done.

Finally in my Password.php script I assume I should make a cookie to allow the site to know which account has successfully logged in but how do I make this cookie secure?

My code is below just want to know if this is a dangerous way of doing things and how the cookie should be made secure thank you for any answers

Ajax Checker

<script type="text/javascript" src="jquery-1.7.1.min.js"/></script>
<script type="text/javascript">
function passWord(){
    var user = document.login.user.value;
    var pass = document.login.pass.value;
    $.ajax({
        url: "Password.php",
        type: "POST",
        data: {'user':user, 'pass':pass},
        success: function (response) {
            if(response!=1){
                //Wrong Password
                $('#divResults').html("The password or username you entered is incorrect.");
            }
        }
    });
    return false;
}
</script>

HTML Form

<form name="login" onsubmit="return passWord()" method="get">
<font color="black"><br>Username or e-mail address:
<br><input type="text" size="40%" name="user" />
<br>You may login with either your assigned username or your e-mail address.
<br><br>Password:<br><input type="password" size="40%" name="pass" />
<br>The password field is case sensitive.<br><br></font>
<input type="submit" value="Log In" />
</form>

Password Checker

<?PHP
  class Bcrypt {
  private $rounds;
  public function __construct($rounds = 12) {
    if(CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input) {
    $hash = crypt($input, $this->getSalt());

    if(strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash) {
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt() {
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count) {
    $bytes = '';

    if(function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if(strlen($bytes) < $count) {
      $bytes = '';

      if($this->randomState === null) {
        $this->randomState = microtime();
        if(function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input) {
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (1);

    return $output;
  }
}

$user = $_REQUEST['user'];
$pass = $_REQUEST['pass'];
$link = mysql_connect('localhost', 'root', 'root');
mysql_select_db("Colleges");
$result = mysql_query("SELECT `Password` FROM `Users` WHERE `Username`=UPPER('" . $user . "')");
$resultV = mysql_fetch_array($result);
$bcrypt = new Bcrypt(10);
$isGood = $bcrypt->verify($pass, $resultV['Password']);
die($isGood);

?>
GFlam
  • 1,089
  • 4
  • 25
  • 38

1 Answers1

4

Your methods are fine for password checking, the javascript doesn't expose the correct passwords or usernames at all. But don't use cookies, use a session instead. Then on every page that is for authenticated users you just include a script to check the session to see if they are authenticated. This way even if they hard link to a protected page or try to jack with the javascript, the session will catch them. If a user is not authenticated in the session you just bounce them back to the login.

user1289347
  • 2,412
  • 1
  • 11
  • 16
  • Okay thank you glad to hear that my methods are fine and I'll use a session variable instead of a cookie. I guess all I need to store in that variable is the username that was authenticated thanks! – GFlam Aug 17 '12 at 20:28
  • yep, store the username or id, then you can just if ($_SESSION['userid']) to validate – user1289347 Aug 17 '12 at 20:30