RealDope Posted March 2, 2015 Share Posted March 2, 2015 (edited) 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 March 2, 2015 by RealDope Quote Link to comment Share on other sites More sharing options...
rwhite35 Posted March 2, 2015 Share Posted March 2, 2015 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. Quote Link to comment Share on other sites More sharing options...
RealDope Posted March 2, 2015 Author Share Posted March 2, 2015 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? Quote Link to comment Share on other sites More sharing options...
rwhite35 Posted March 3, 2015 Share Posted March 3, 2015 (edited) 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 March 3, 2015 by rwhite35 Quote Link to comment Share on other sites More sharing options...
rwhite35 Posted March 3, 2015 Share Posted March 3, 2015 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. Quote Link to comment Share on other sites More sharing options...
RealDope Posted March 3, 2015 Author Share Posted March 3, 2015 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.