Reputation: 998
I would just like to have some feedback on some php code for a website, because it's the first time I'm writing code that will properly be used on public websites and I'm a little paranoid.
This code is at the top of a signup page with a post form that sends back to itself, so I check if the form has been completed by checking if the POST "isset".
It's for a signup page :
<?php
if (isset($_POST['email'])) {
$thanks = '';
$name = $_POST['name'];
$email = $_POST['email'];
$postcode = $_POST['postcode']; //not used
$password = $_POST['password'];
//connects to database, DB variable is dbConnection
require_once("include/database_connect_test.php");
//First check email isn't already on DB
$sql = 'SELECT * FROM `user_profile` WHERE email=?';
$stmt = $dbConnection->prepare($sql);
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
$num_of_rows = $stmt->num_rows;
$stmt->close();
if($num_of_rows>0)
$thanks = 'This email has already been registered';
//If not, create profile
else{
require_once('generate_uuid.php');
$hash = password_hash($password, PASSWORD_BCRYPT); //password_verify(pass, hash) to verify
$sql = 'INSERT INTO `user_profile`(`name`, `email`, `hash`, `uuid`) VALUES (?,?,?,?)';
$stmt = $dbConnection->prepare($sql);
$stmt->bind_param('ssss', $name, $email, $hash, $uuid);
$stmt->execute();
$stmt->close();
$thanks = 'Thank you for signing up!'; //used in the html
}
}?>
Thanks in advance for any input :)
Upvotes: 2
Views: 78
Reputation: 48267
Unrelated to security, you should use the Post-Redirect-Get pattern. For now, when user sees "Thanks" message, if they hit "refresh" on their browser, it will try to re-register them.
Upvotes: 1
Reputation: 22760
Here is a small collection of PHP features and functions that can be useful to your code block:
$_POST['email']
is a valid email shape: if(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){...}
$options['cost']
value for your Password_hash
. THe default standard is 10 which is a bit weak, depending on your server specs I would say you want at least 12 cost value. $options['cost'] = 12; $hash = password_hash($password, PASSWORD_BCRYPT,$options);
I would recommend running your $_POST
variables through a custom stripper function such as a preg_replace
Regex. I would personally always use a Regex routine to strip out unwanted characters from a submitted string.
Your uuid
value with the name of id
I would expect it to be a counter integer but it's cast to the binding as a string(S
), so not sure about what type of variable that is?
Also you can improve your security by researching and looking into Cross Site Scripting and how to avoid this, basically set a unique value in your submitting form, and save this value to a $_SESSION
and then compare, this will much more ensure that things sent to your PHP / MySQL will come and be accepted only from your sending form.
On a related security note, you can also setup a Content Security Policy header for your website.
Upvotes: 1
Reputation: 146490
I see nothing particularly wrong from the security standpoint. You're doing the most important things right:
password_hash()
Being picky:
The fact that $_POST['email']
is set doesn't imply other post variables will also exist. You should really verify all input because filling your form is not the only way to submit data to your script. But rather than security is a way to ensure you can take benefit of PHP notices by avoiding false positives.
Also, you may like the filter extension, a feature that's been available for a while but is not particularly widespread and allows code like this:
$name = filter_input(INPUT_POST, 'name');
$email = filter_input(INPUT_POST, 'email');
$postcode = filter_input(INPUT_POST, 'postcode'); //not used
$password = filter_input(INPUT_POST, 'password');
I've never liked the technique of counting rows in a result set to validate if a user exists because it's too dependent on external factors (database driver, query function used...). I simply fetch the row, which also allows to retrieve additional user data for session variables.
I suppose that $uuid
is defined inside generate_uuid.php
but when you look at code it seems to pop up from nowhere. A better structure is that your included files load functions and then you call those functions:
$uuid = generate_uuid();
$stmt->bind_param('ssss', $name, $email, $hash, $uuid);
... but, as I said, none of these factors affect security.
Upvotes: 3
Reputation: 1289
Right now someone is able to for example put javascript as his username, and if you added a comments section that javascript would run. Your script is vulnerable to xss injection. Use mysqli_real_escape_string and htmlpurifier.
Upvotes: 0