Jump to content

Login and Registration Security


RealDope

Recommended Posts

I'm making a mobile app and using PHP to store and verify users in MySQL. I'm not very well-informed on the topic of security, but my plan here was to follow the logic:

 

1. User makes an HTTPS connection to register.php including username, password, and email.

2. PHP checks availability and if both username and email are open, it hashes the password and stores the 3 fields.

3. Returns success

 

Login:

 

1. User makes an HTTPS connection to login.php including username and password.

2. PHP hashes the password and compares

3. If successful, generates a random 16 character token and saves that, along with the current time, to the database.

4. Returns the token

 

Subsequent requests can be made using the token.

 

My questions:

 

1. Is token expiration a necessary feature? If so, how should I handle "refreshing" them to avoid requiring re-login?

2. Is my code safe? I'm not great with security or PHP, and I'd rather not leave a gaping hole in my system here.

 

Register.php

<?php
	$sql_db = "db_name";
	$sql_host = "db_host";
	$sql_user = "root"; # I don't actually use root
	$sql_pass = "random_pass";
	require "password_compat-master/lib/password.php";
	
	if(!isset($_POST['username'])) {
		echo "No username given!";
		die();
	}
	if(!isset($_POST['password'])) {
		echo "No password given!";
		die();
	}
	if(!isset($_POST['email'])) {
		echo "No email given!";
		die();
	}

	$username = filter_input(INPUT_POST, "username");
	$email = filter_input(INPUT_POST, "email");
	$password = filter_input(INPUT_POST, "password");
	try {
		$db = new pdo('mysql:dbname=' . $sql_db . ";host=" . $sql_host, $sql_user, $sql_pass, array(PDO::ATTR_PERSISTENT => true));
	}
	catch(Exception $e) {
		echo "Error connecting to database";
		#echo $e->getMessage();
	}
	
	if($db == null) {
		echo "Failed to connect to database";
		die();
	}
	$hash = password_hash($password, PASSWORD_BCRYPT);
	
	if($hash == false) {
		echo "Failed to hash password";
		die();
	}
	
	$register_query = $db->prepare('INSERT INTO users (username, password, email) VALUES (?, ?, ?);');
	$register_query->execute(array($username, $hash, $email));
	
	if($register_query->errorCode() == 23000) {
		$pieces = explode(' ', $register_query->errorInfo()[2]);
		$table = array_pop($pieces);
		if($table == "'username'") {
			echo "Username already in use!";
			die();
		} elseif($table == "'email'") {
			echo "Email already in use!";
			die();
		}
	}
	elseif($register_query->errorCode() == 00000) {
		echo "Registration successful!";
		die();
	}
	else {
		echo "Registration failed!";
		die();
	}
?>

Login.php

<?php
	$sql_db = "db_name";
	$sql_host = "db_host";
	$sql_user = "root"; # I don't actually use root
	$sql_pass = "db_pass";
	require "password_compat-master/lib/password.php";
	
	if(!isset($_POST['username'])) {
		echo "No username given!";
		die();
	}
	if(!isset($_POST['password'])) {
		echo "No password given!";
		die();
	}

	$username = filter_input(INPUT_POST, "username");
	$password = filter_input(INPUT_POST, "password");
	try {
		$db = new pdo('mysql:dbname=' . $sql_db . ";host=" . $sql_host, $sql_user, $sql_pass, array(
			PDO::ATTR_PERSISTENT => true
		));
	}
	catch(Exception $e) {
		echo "Error connecting to database";
		#echo $e->getMessage();
	}
	
	if($db == null) {
		echo "Failed to connect to database";
		die();
	}
	$existing_hash_query = $db->prepare("SELECT * FROM users WHERE username = ?;");
	$existing_hash_query->execute(array($username));
	
	$row = $existing_hash_query->fetch(PDO::FETCH_ASSOC);
	
	$hash_pw = $row['password'];
	
	if($hash_pw == null || !(password_verify($password, $hash_pw))) {
		echo "Username or password incorrect!";
		die();
	}
	$token = bin2hex(openssl_random_pseudo_bytes(16));
	$insert_token_query = $db->prepare("UPDATE users SET token = ?, tokentime = NOW() WHERE username = ?;");
	$insert_token_query->execute(array($token, $username));
	
	if ($insert_token_query->errorCode() != 0000) {
		echo "Error inserting token";
		die();
	}
	
	echo $token;
?>

The library I'm using to hash and verify is here.

Edited by RealDope
Link to comment
Share on other sites

Input looks good.  PDO good, hashing looks good.  Unless I'm missing it, I don't see where you're assigning the token to a session variable.  Something like:

session_start();
$_SESSION['authorized'] = $token; 

Then on subsequent pages, you would check your users token to insure they're authorized to run the script.  That would save you multiple trips to the database in order to check the token there.

Link to comment
Share on other sites

Input looks good.  PDO good, hashing looks good.  Unless I'm missing it, I don't see where you're assigning the token to a session variable.  Something like:

session_start();
$_SESSION['authorized'] = $token; 

Then on subsequent pages, you would check your users token to insure they're authorized to run the script.  That would save you multiple trips to the database in order to check the token there.

 

Thanks, but this is just for the purposes of authenticating mobile app users. I'm not actually using this on a website with sessions and multiple pages.

 

Any idea on token expiration? Is this a necessary feature for long-term "logged in" on mobile apps?

Link to comment
Share on other sites

 

 

Any idea on token expiration? Is this a necessary feature for long-term "logged in" on mobile apps?

 

Okay, so if I understand the logic, the user is on their mobile device (iPhone/Android) and they've logged in through the OS web interface (UIKit for example).  Once login or register scripts are done, that memory is automatically released.  There isn't a 'persistent' state or Automatic Reference Counting(ARC) like with iOS.  I think you would need to instance an object inside your app, store the token in memory there, and perhaps re query the database.  PHP is stateless.  

 

Alternatively, maybe you could write the token to a flat file and compare the token stored in iOS memory to the one written in the text file.  Just thinking how I might approach the problem.

Edited by rwhite35
Link to comment
Share on other sites

This is why I shouldn't visit forums... Now I'm curious as to how to solve your problem...

 

Looking around a bit and you may want to consider a framework like Yii.  It allows machine-to-machine interaction is a RESTful manner (behind the scenes).  

 

I would characterize my second answer as "Web Services" on the cheap...  Reading in a flat file.  But a web services framework may be the better solution.  

 

At any rate, I'm going to build a similar prototype which will satisfy my curiosity -- thanks to your post. 

Link to comment
Share on other sites

This is why I shouldn't visit forums... Now I'm curious as to how to solve your problem...

 

Looking around a bit and you may want to consider a framework like Yii.  It allows machine-to-machine interaction is a RESTful manner (behind the scenes).  

 

I would characterize my second answer as "Web Services" on the cheap...  Reading in a flat file.  But a web services framework may be the better solution.  

 

At any rate, I'm going to build a similar prototype which will satisfy my curiosity -- thanks to your post. 

I'm not sure we're on the same page. I'm not trying to create any kind of iOS -> PHP session.

 

The idea is just to prevent requiring the password to be sent for every request from a mobile user to the server. After the initial login, they can use the token as verification of their identity until the token either expires or is revoked. The token users send is compared to the one in the database paired with their username, and if it matches and is still valid, the server accepts the request. If the token is compromised, it can easily be revoked without risk of the user losing access to their account.

 

I'm looking more for general security logic answers, not particularly specific to PHP.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.