Sinisterly
Secure registration and log in script - Part 2 of 2 - The Log In - Printable Version

+- Sinisterly (https://sinister.li)
+-- Forum: Coding (https://sinister.li/Forum-Coding)
+--- Forum: PHP (https://sinister.li/Forum-PHP)
+--- Thread: Secure registration and log in script - Part 2 of 2 - The Log In (/Thread-Secure-registration-and-log-in-script-Part-2-of-2-The-Log-In)

Pages: 1 2


RE: Secure registration and log in script - Part 2 of 2 - The Log In - hellomen - 11-13-2013

(11-13-2013, 10:09 AM)shp0ngl3 Wrote: I give up.. Seriously, I give up! First you provide a function that uses sha1 and md5 x 3 times or something (Yes I'm going back to the IRC chat now).. Both me and @1llusion tells you that it is NOT secure, and you keep arguing that you're method is secure because you use it more than one time and have salts! Then @Anima Templi tries to help you but you refuse to listen to his suggestion. On top of this you admit that you are new to PHP, and still you have the balls to tell me that after my 13 years of experience I still have no clue what I'm talking about.. Consider this my last time helping you out.

Why is it more secure you ask?
- When done properly you need two attacks to get to the key. You can even store it on a separate server if you want. So by using the key file you will have to break into the actual server not just dump it with a simple sql injection
Code:
concat_ws(0x3a,username,password,salt)
- On top of the HMAC you have a blowfish hash which uses a unique salt for each hash that you do not need to store. The algorithm handles this on its own.
- The key stored has a much stronger cryptographic entropy than your average salt stored in a database. I mean, this doesn't provide good entropy

MyBB's salt generator:
Code:
function random_str($length="8") { $set = array("a","A","b","B","c","C","d","D","e","E","f","F","g","G","h","H","i","I","j","J","k","K","l","L","m","M","n","N","o","O","p","P","q","Q","r","R","s","S","t","T","u","U","v","V","w","W","x","X","y","Y","z","Z","1","2","3","4","5","6","7","8","9"); $str = ''; for($i = 1; $i <= $length; ++$i) { $ch = my_rand(0, count($set)-1); $str .= $set[$ch]; } return $str; }

I will leave you with a blog post from Mozilla security team about how to store passwords securely, and you will see that the method used is the one described here.

http://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-password-storage/

well that explained it prety much thanks for the information.


RE: Secure registration and log in script - Part 2 of 2 - The Log In - levi01 - 03-29-2014

This how i use it, this is build on own experiences and its pretty safe and prepared for the future with " PDO"

common.php
Spoiler:
PHP Code:
<?php $username = "******"; $password = "*******"; $host = "*******"; $dbname = "*******"; $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); try { $db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options); } catch(PDOException $ex) { die("Failed to connect to the database: " . $ex->getMessage()); } $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { function undo_magic_quotes_gpc(&$array) { foreach($array as &$value) { if(is_array($value)) { undo_magic_quotes_gpc($value); } else { $value = stripslashes($value); } } } undo_magic_quotes_gpc($_POST); undo_magic_quotes_gpc($_GET); undo_magic_quotes_gpc($_COOKIE); } header('Content-Type: text/html; charset=utf-8'); session_start();


login.php
Spoiler:
PHP Code:
<?php require("common.php"); $submitted_username = ''; if(!empty($_POST)) { $query = " SELECT id, username, password, salt, email FROM users WHERE username = :username "; $query_params = array( ':username' => $_POST['username'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $login_ok = false; $row = $stmt->fetch(); if($row) { $check_password = hash('sha256', $_POST['password'] . $row['salt']); for($round = 0; $round < 65536; $round++) { $check_password = hash('sha256', $check_password . $row['salt']); } if($check_password === $row['password']) { $login_ok = true; } } if($login_ok) { unset($row['salt']); unset($row['password']); $_SESSION['user'] = $row; header("Location: private.php"); die("Redirecting to: private.php"); } else { print("Login Failed."); $submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8'); } } ?> <h1>Login</h1> <form action="login.php" method="post"> Username:<br /> <input type="text" name="username" value="<?php echo $submitted_username; ?>" /> <br /><br /> Password:<br /> <input type="password" name="password" value="" /> <br /><br /> <input type="submit" value="Login" /> </form> <a href="register.php">Register</a>


memberlist.php
Spoiler:
PHP Code:
<?php require("common.php"); if(empty($_SESSION['user'])) { header("Location: login.php"); die("Redirecting to login.php"); } $query = " SELECT id, username, email FROM users "; try { $stmt = $db->prepare($query); $stmt->execute(); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $rows = $stmt->fetchAll(); ?> <h1>Memberlist</h1> <table> <tr> <th>ID</th> <th>Username</th> <th>E-Mail Address</th> </tr> <?php foreach($rows as $row): ?> <tr> <td><?php echo $row['id']; ?></td> <td><?php echo htmlentities($row['username'], ENT_QUOTES, 'UTF-8'); ?></td> <td><?php echo htmlentities($row['email'], ENT_QUOTES, 'UTF-8'); ?></td> </tr> <?php endforeach; ?> </table> <a href="private.php">Go Back</a><br />

edit_account.php

Spoiler:
PHP Code:
<?php require("common.php"); if(empty($_SESSION['user'])) { header("Location: login.php"); die("Redirecting to login.php"); } if(!empty($_POST)) { if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { die("Invalid E-Mail Address"); } if($_POST['email'] != $_SESSION['user']['email']) { $query = " SELECT 1 FROM users WHERE email = :email "; $query_params = array( ':email' => $_POST['email'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $row = $stmt->fetch(); if($row) { die("This E-Mail address is already in use"); } } if(!empty($_POST['password'])) { $salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647)); $password = hash('sha256', $_POST['password'] . $salt); for($round = 0; $round < 65536; $round++) { $password = hash('sha256', $password . $salt); } } else { $password = null; $salt = null; } $query_params = array( ':email' => $_POST['email'], ':user_id' => $_SESSION['user']['id'], ); if($password !== null) { $query_params[':password'] = $password; $query_params[':salt'] = $salt; } $query = " UPDATE users SET email = :email "; if($password !== null) { $query .= " , password = :password , salt = :salt "; } $query .= " WHERE id = :user_id "; try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $_SESSION['user']['email'] = $_POST['email']; header("Location: private.php"); die("Redirecting to private.php"); } ?> <h1>Edit Account</h1> <form action="edit_account.php" method="post"> Username:<br /> <b><?php echo htmlentities($_SESSION['user']['username'], ENT_QUOTES, 'UTF-8'); ?></b> <br /><br /> E-Mail Address:<br /> <input type="text" name="email" value="<?php echo htmlentities($_SESSION['user']['email'], ENT_QUOTES, 'UTF-8'); ?>" /> <br /><br /> Password:<br /> <input type="password" name="password" value="" /><br /> <i>(leave blank if you do not want to change your password)</i> <br /><br /> <input type="submit" value="Update Account" /> </form>



RE: Secure registration and log in script - Part 2 of 2 - The Log In - levi01 - 03-29-2014

This how i use it, this is build on own experiences and its pretty safe and prepared for the future with " PDO"

common.php
Spoiler:
PHP Code:
<?php $username = "******"; $password = "*******"; $host = "*******"; $dbname = "*******"; $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); try { $db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options); } catch(PDOException $ex) { die("Failed to connect to the database: " . $ex->getMessage()); } $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { function undo_magic_quotes_gpc(&$array) { foreach($array as &$value) { if(is_array($value)) { undo_magic_quotes_gpc($value); } else { $value = stripslashes($value); } } } undo_magic_quotes_gpc($_POST); undo_magic_quotes_gpc($_GET); undo_magic_quotes_gpc($_COOKIE); } header('Content-Type: text/html; charset=utf-8'); session_start();


login.php
Spoiler:
PHP Code:
<?php require("common.php"); $submitted_username = ''; if(!empty($_POST)) { $query = " SELECT id, username, password, salt, email FROM users WHERE username = :username "; $query_params = array( ':username' => $_POST['username'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $login_ok = false; $row = $stmt->fetch(); if($row) { $check_password = hash('sha256', $_POST['password'] . $row['salt']); for($round = 0; $round < 65536; $round++) { $check_password = hash('sha256', $check_password . $row['salt']); } if($check_password === $row['password']) { $login_ok = true; } } if($login_ok) { unset($row['salt']); unset($row['password']); $_SESSION['user'] = $row; header("Location: private.php"); die("Redirecting to: private.php"); } else { print("Login Failed."); $submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8'); } } ?> <h1>Login</h1> <form action="login.php" method="post"> Username:<br /> <input type="text" name="username" value="<?php echo $submitted_username; ?>" /> <br /><br /> Password:<br /> <input type="password" name="password" value="" /> <br /><br /> <input type="submit" value="Login" /> </form> <a href="register.php">Register</a>


memberlist.php
Spoiler:
PHP Code:
<?php require("common.php"); if(empty($_SESSION['user'])) { header("Location: login.php"); die("Redirecting to login.php"); } $query = " SELECT id, username, email FROM users "; try { $stmt = $db->prepare($query); $stmt->execute(); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $rows = $stmt->fetchAll(); ?> <h1>Memberlist</h1> <table> <tr> <th>ID</th> <th>Username</th> <th>E-Mail Address</th> </tr> <?php foreach($rows as $row): ?> <tr> <td><?php echo $row['id']; ?></td> <td><?php echo htmlentities($row['username'], ENT_QUOTES, 'UTF-8'); ?></td> <td><?php echo htmlentities($row['email'], ENT_QUOTES, 'UTF-8'); ?></td> </tr> <?php endforeach; ?> </table> <a href="private.php">Go Back</a><br />

edit_account.php
Spoiler:
PHP Code:
<?php require("common.php"); if(empty($_SESSION['user'])) { header("Location: login.php"); die("Redirecting to login.php"); } if(!empty($_POST)) { if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { die("Invalid E-Mail Address"); } if($_POST['email'] != $_SESSION['user']['email']) { $query = " SELECT 1 FROM users WHERE email = :email "; $query_params = array( ':email' => $_POST['email'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $row = $stmt->fetch(); if($row) { die("This E-Mail address is already in use"); } } if(!empty($_POST['password'])) { $salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647)); $password = hash('sha256', $_POST['password'] . $salt); for($round = 0; $round < 65536; $round++) { $password = hash('sha256', $password . $salt); } } else { $password = null; $salt = null; } $query_params = array( ':email' => $_POST['email'], ':user_id' => $_SESSION['user']['id'], ); if($password !== null) { $query_params[':password'] = $password; $query_params[':salt'] = $salt; } $query = " UPDATE users SET email = :email "; if($password !== null) { $query .= " , password = :password , salt = :salt "; } $query .= " WHERE id = :user_id "; try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $_SESSION['user']['email'] = $_POST['email']; header("Location: private.php"); die("Redirecting to private.php"); } ?> <h1>Edit Account</h1> <form action="edit_account.php" method="post"> Username:<br /> <b><?php echo htmlentities($_SESSION['user']['username'], ENT_QUOTES, 'UTF-8'); ?></b> <br /><br /> E-Mail Address:<br /> <input type="text" name="email" value="<?php echo htmlentities($_SESSION['user']['email'], ENT_QUOTES, 'UTF-8'); ?>" /> <br /><br /> Password:<br /> <input type="password" name="password" value="" /><br /> <i>(leave blank if you do not want to change your password)</i> <br /><br /> <input type="submit" value="Update Account" /> </form>


private.php
Spoiler:
PHP Code:
<?php require("common.php"); if(empty($_SESSION['user'])) { header("Location: login.php"); die("Redirecting to login.php"); } ?> Hello <?php echo htmlentities($_SESSION['user']['username'], ENT_QUOTES, 'UTF-8'); ?>, This protection i always use. Grt levi01 ;) !<br /> <a href="memberlist.php">Memberlist</a><br /> <a href="edit_account.php">Edit Account</a><br /> <a href="logout.php">Logout</a>


register.php
Spoiler:
PHP Code:
<?php require("common.php"); if(!empty($_POST)) { if(empty($_POST['username'])) { die("Please enter a username."); } if(empty($_POST['password'])) { die("Please enter a password."); } if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { die("Invalid E-Mail Address"); } $query = " SELECT 1 FROM users WHERE username = :username "; $query_params = array( ':username' => $_POST['username'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $row = $stmt->fetch(); if($row) { die("This username is already in use"); } $query = " SELECT 1 FROM users WHERE email = :email "; $query_params = array( ':email' => $_POST['email'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } $row = $stmt->fetch(); if($row) { die("This email address is already registered"); } $query = " INSERT INTO users ( username, password, salt, email ) VALUES ( :username, :password, :salt, :email ) "; $salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647)); $password = hash('sha256', $_POST['password'] . $salt); for($round = 0; $round < 65536; $round++) { $password = hash('sha256', $password . $salt); } $query_params = array( ':username' => $_POST['username'], ':password' => $password, ':salt' => $salt, ':email' => $_POST['email'] ); try { $stmt = $db->prepare($query); $result = $stmt->execute($query_params); } catch(PDOException $ex) { die("Failed to run query: " . $ex->getMessage()); } header("Location: login.php"); die("Redirecting to login.php"); } ?> <h1>Add new admin</h1> <form action="register.php" method="post"> Username:<br /> <input type="text" name="username" value="" /> <br /><br /> E-Mail:<br /> <input type="text" name="email" value="" /> <br /><br /> Password:<br /> <input type="password" name="password" value="" /> <br /><br /> <input type="submit" value="Register" /> </form>


logout.php
Spoiler:
PHP Code:
<?php require("common.php"); unset($_SESSION['user']); header("Location: login.php"); die("Redirecting to: login.php");


Thats it, configure it at your own wishes Wink