I've been looking around and can't find a place that is showing me an effective way to do this. Currently I have a query that runs when the user submits a form:
$query = "UPDATE user SET username='$_POST[username]',
nicename='$_POST[nicename]',
email='$_POST[email]',
password=(SHA1)'$_POST[password]',
position='$_POST[position]',
race='$_POST[race]',
type='$_POST[type]' WHERE username=$_SESSION[admin_login]";
I'm not sure on how to get this to actually work correctly. Sorry if it's been asked before, but I can't find a good solution to this anywhere. Thanks in advance for any help.
First of all entire thing is wrong : Why?
Because first of all you need to sanitize the input, which you are not doing, atleast you should use mysqli_real_escape_string like this :
$nicename = mysqli_real_escape_string($connect, $_POST['nicename']);
Reference
Secondly you should encrypt the password before you use it in your query like assign your encrypted password to a variable and than use it in your query, like this :
$hashed_pass = sha1($_POST['password']);
//Query goes here
and last but not the least instead of using super global $_SESSION variable directly in your query, use concatenate it.. like this
WHERE username='".$_SESSION[admin_login]."'";
Firstly, always remember Little Bobby Tables. Inserting data like that can lead to SQL injection attacks just like in that cartoon. I'd highly suggest you use prepared statements, this is a feature in both PDO and MySQLi which are methods of reading and writing to a database using PHP, some info on: PDO and some info on: MySQLi.
Whichever you choose to go with doesn't really matter, it's more about personal preference. I like PDO, so here's an example of binding the data and then executing your query using PDO:
$dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$password = sha1($_POST[password]);
$stmt = $dbh->prepare("UPDATE user SET username = :username, nicename = :nicename, email = :email, password = :password, position = :position, race = :race, type = :type WHERE = :username");
$stmt->bindParam(':username', $_POST['username']);
$stmt->bindParam(':nicename', $_POST['nicename']);
$stmt->bindParam(':email', $_POST['email']);
$stmt->bindParam(':password', $password);
$stmt->bindParam(':position', $_POST['position']);
$stmt->bindParam(':race', $_POST['race']);
$stmt->bindParam(':type', $_POST['type']);
$stmt->bindParam(':username', $_SESSION['admin_login']);
$stmt->execute();
$_POST and $_GET arrays can contain dangerous data, so you need prepare data from these arrays before inserting them into DB.
First, you need typecast values to right data types. In PHP you can use followed constructions: (string) for string data, (int) and (float) for numeric data, (bool) for boolean data.
Field email necessary checked for valid email, use Regex for it.
Follow code is sample of checking data:
<?php
$link = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
$username = mysqli_real_escape_string($link, (string) $_POST['username']);
$nicename = mysqli_real_escape_string($link, (string) $_POST['nicename']);
$email = mysqli_real_escape_string($link, (string) $_POST['email']);
$email = preg_replace( '/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*#[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$/', $email );
$password = sha1((string) $_POST['password']);
$position = mysqli_real_escape_string($link, (string) $_POST['position']);
$race = mysqli_real_escape_string($link, (string) $_POST['race']);
$type = mysqli_real_escape_string($link, (string) $_POST['type']);
$admin = $_SESSION['admin_login'];
$query = "UPDATE `user`
SET `username`='$username',
`nicename`='$nicename',
`email`='$email',
`password`='$password',
`position`='$position',
`race`='$race',
`type`='$type'
WHERE `username`='$admin'";
mysqli_query($link, $query);
mysqli_close($link);
Related
my code looks like this (just a example, at a few parts of my projekt there are a lot of variables more then in this example):
$pdo = new PDO('mysql:host=localhost;dbname=nameofdb;charset=utf8','dbuser','dbpass');
$surname = htmlspecialchars($_POST["surname"]);
$lastname = htmlspecialchars($_POST["lastname"]);
$street = htmlspecialchars($_POST["street"]);
$username = htmlspecialchars($_POST["username"]);
$sql = $pdo->prepare("UPDATE customer SET surname = ?,lastname = ?,street = ? WHERE username = ?");
$sql->execute(array($surname, $lastname, $street,$username));
$pdo->close();
$sql->close();
All POST variables come from forms that users can(must) fill out, so it is important that it is as safe as possible.
Sorry for this (maybe) beginner question(s), but i'm new in the PDO game, still read a lot but want to see what you people say to that code.
Please tell me what i can optimize, and above all WHY, so i can learn!
I am trying to pass text variables from a form form a previous page and insert it into a SQL table. The problem I'm having is on the line: $sql = "INSERT INTO CUSTOMER (fname, lname) VALUES ($firstName, 'smith')";.
If I were to replace "$firstName" with a basic string like "John", the name and last name would be inserted into the SQL table as intended. But, since I'm trying to insert a text value gathered from a form, I need to be able to use the non-static variables but for some reason that I cannot figure out, doesn't work. From everything I read online, just adding the variable into the parameter should make it work but it just doesn't.
I'm very new to this so I'm sorry if my question is confusing. Also, I am fairly certain that the issue does not lie on the file with the form on it.
Any help would be so awesome. thanks!
Here is the code that I'm having trouble with:
<html>
<?php
$username = $_Post['username'];
$email = $_Post['email'];
$phone = $_Post['number'];
$firstName = $_Post['firstName'];
$lastName = $_Post['lastName'];
$address = $_Post['address'];
$password = $_Post['password'];
$conn = new mysqli('localhost','root','password','database');
if($conn->connect_error){
echo "$conn->connect_error";
die("Connection Failed : ". $conn->connect_error);
} else {
$sql = "INSERT INTO CUSTOMER (fname, lname) VALUES ($firstName, 'smith')";
$conn->query($sql);
echo $execval;
echo "Registration successfully...";
$conn->close();
}
?>
</html>
To summarize all other answers,
First, you should replace $firstName to '$firstName' because otherwise the text (e.g. "John") will be placed in your query without quotes, like this: INSERT INTO CUSTOMER (fname, lname) VALUES (John, 'smith') This results in an error because it thinks John is some sort of variable.
Second, your code is vulnerable to SQL Injection. This is a very serious vulnerability in your website as attackers can use it to read your entire database, and in this case, even create entries in your database, which can result in attackers being able to completely take over your site by writing files!
More in-depth info here: https://owasp.org/www-community/attacks/SQL_Injection
The important thing is that the user can control the $firstName variable that you use in $sql = "INSERT INTO CUSTOMER (fname, lname) VALUES ('$firstName', 'smith')"; This way the attacker can change the query at that point. He could for example use the payload ', 'a'); DROP TABLE CUSTOMER;-- to delete all information in the CUSTOMER table.
There are multiple ways to prevent this, but the easiest is to use prepared statements. It looks something like this:
$stmt = $dbConnection->prepare("INSERT INTO CUSTOMER (fname, lname) VALUES (?, ?)");
$stmt->bind_param('ss', $param_firstName, $param_lastName);
$param_firstName = $firstName; // New line
$param_lastName = $lastName; // New line
$stmt->execute();
This way you make sure MySQL doesn't interpret any user input as SQL code, but only as values.
Again, more in-depth information here:
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
If you get user input to insert into a database you should always use "Prepared statements" to prevent "SQL injection" or comparable things.
Check here:
PHP Prepared Statements - w3school
The solution of Aashish gaba should work as well but it's unsecure.
This should work for your code:
<?php
$username = $_POST['username'];
$email = $_POST['email'];
$phone = $_POST['number'];
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$address = $_POST['address'];
$password = $_POST['password'];
$conn = new mysqli('localhost','root','password','database');
if($conn->connect_error){
echo "$conn->connect_error";
die("Connection Failed : ". $conn->connect_error);
} else {
$stmt = $conn->prepare("INSERT INTO CUSTOMER (fname, lname) VALUES (?, ?)");
$stmt->bind_param("ss",$fname, $lname);
// set parameters and execute
$fname = $firstName;
$lname = $lastName;
$stmt->execute();
echo $execval;
echo "Registration successfully...";
$conn->close();
}
?>
A nice to have of a prepared statement is the fact that they are reusable like:
// set parameters and execute
$fname = "person1_fname";
$lname = "person1_lname";
$stmt->execute();
$fname = "person2_fname";
$lname = "person2_lname";
$stmt->execute();
Also don't forget to use somthing to prevent other injections if you print a value to a user. Like:
echo "Registration successfully for" . htmlspecialchars($_Post['username']);
In addition save the password as hash (with a secure hashfunction) into the database.
As a quick fix you can update your $sql like this:
$sql = "INSERT INTO CUSTOMER (fname, lname) VALUES ('{$firstName}', '{$lastName}')";
But now your code is vulnerable to SQL Injection.
At least you should use mysqli escape function before your $sql statement, like this:
$firstName = $mysqli->real_escape_string($firstName);
$lastName = $mysqli->real_escape_string($lastName);
But I strongly recommend you considering using more advanced options like PDO for the further steps and Production environments.
Remplace $firstName to '$firstName'.
or use prepared request
I have been on this all day and after searching many websites (including this one) i came to the conclusion that my question hasn't been asked before probably due to my incompetence.
I have a prepared statement here that i would like to update my password field in my DB depending on the username and email, the reason it is updating and not inserting is because its part of my security to not approve site photographers until they have been sent a link
<?php
if (isset($_POST['approved-photographer'])) {
require 'dbh.php';
$username = $_POST['username'];
$email = $_POST['mail'];
$password = $_POST['password'];
$password2 = $_POST['password-repeat'];
if (empty($username) || empty($email) || empty($password) ||
empty($password2))
{
header("location:signup.php?error=emptyfields&username=" . $username
. "&mail=.$email");
exit();
} elseif ($password !== $password2) {
header("location:approvedphoto.php?error=passwordcheck&username=" .
$username . "&mail=" . $email);
exit();
} else {
$sql = "SELECT Password
FROM photographers
WHERE Username= '$username'
AND Email= '$email'";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location:approvedphoto.php?error=sqlerror");
exit();
} else {
$sql = "INSERT INTO photographers (Password) VALUES (?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location:approvedphoto.php?error=sqlerror2");
exit();
} else {
$hashedpwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "s", $hashedpwd);
mysqli_stmt_execute($stmt);
header("location:signin.php?signup=success");
exit();
}
}
}
}
Any Help would be greatly appreciated. Thanks for reading
The short answer for your MySQLi usage is you didn't bind the parameters, which you can do using mysqli_stmt_bind_param (Future readers, this last statement is now irrelevant due to edits). Overall your sql statements post-editing seem unclear, you would typically either be updating a password (in which case you need a WHERE clause so you don't update everyone's password), or you should be inserting a new user with a password.
This is a more-or-less tangential answer, but I would like to throw my hat into the ring for the use of PDO (instead of mysqli). MySQLi works with only one form of database flavor, MySQL. Additionally it allows for a much less object-oriented solution to db interactions. Here's an example of how you could accomplish this through PDO:
//specifies the driver, ip/database etc. Swap out for your ip and database used
$driverStr = 'mysql:host=<ip>;dbname=<database>;charset=utf8';
//you can set some default behaviors here for your use, I put some examples
//I left a link below so you can see the different options
$options = [
//spew exceptions on errors, helpful to you if you have php errors enabled
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
//substite what you need for username/password here as well, $options can be omitted
$conn = new PDO($driverStr, '<username>', '<password>', $options);
Link to the aforementioned attributes
Now that we've made our connection:
//I used a "named parameter", e.g. :password, instead of an anonymous parameter
$stmt = $conn->prepare("UPDATE Photographers SET password = :password WHERE Username = :username");
//with our prepared statement, there's a few ways of executing it
//1) Using #bind*
//there's also #bindValue for not binding a variable reference
//for params, PARAM_STR is default and can be safely omitted
$stmt->bindParam(':password', $password, PDO::PARAM_STR);
$stmt->bindParam(':username', $username);
$stmt->execute();
//2) Using execute directly
$stmt->execute(['password' => $password, 'username' => $username]);
Then, were the statement a query and not just a database update/insert, we can simply retrieve the results of the statement. By using #bindParam you can also just update the variable's values and re-execute the statement if you like, which may be useful to you for some other statements.
//see #fetch and #fetchAll's documentation for the returned data formatting
$results = $stmt->fetchAll(PDO::FETCH_OBJ); //return it as a php object
$results = $stmt->fetch(PDO::FETCH_NUM)[0]; //unsafely retrieve the first value as a number
Over the years I've found this to be much cleaner and more managable than any of the mysqli_* or even the deprecated mysql_* methods.
I get an error on the last line on mysqli_escape_string($hash)); by using the following code:
$hash = md5( rand(0,1000) );
$stmt = $mysqli->prepare("INSERT INTO users (username, password, hash) VALUES (?, ?, mysqli_escape_string($hash))");
$password = md5($password);
$stmt->bind_param('ss', $username, $password, mysqli_escape_string($hash));
It says, that the mysqli_escape_string($hash)) is a non-object.
But using only $hash instead doesn't help either
Can someone help?
There are far too many things wrong with your code and will be extremely difficult to provide a solution by fixing what you have now.
Firstly, MD5 is no longer considered safe to use for password storage.
Consult:
https://security.stackexchange.com/questions/19906/is-md5-considered-insecure
https://en.wikipedia.org/wiki/MD5
Plus, you're not using prepared statements correctly.
Consult: http://php.net/manual/en/mysqli.prepare.php
As I stated, the mysqli_escape_string() function requires a database connection be passed as the first parameter:
http://php.net/manual/en/mysqli.real-escape-string.php
Do yourself a favor and use this, one of ircmaxell's answers https://stackoverflow.com/a/29778421/
Pulled from his answer:
Just use a library. Seriously. They exist for a reason.
PHP 5.5+: use password_hash()
PHP 5.3.7+: use password-compat (a compatibility pack for above)
All others: use phpass
Don't do it yourself. If you're creating your own salt, YOU'RE DOING IT WRONG. You should be using a library that handles that for you.
$dbh = new PDO(...);
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $dbh->prepare("insert into users set username=?, email=?, password=?");
$stmt->execute([$username, $email, $hash]);
And on login:
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $dbh->prepare($sql);
$result = $stmt->execute([$_POST['username']]);
$users = $result->fetchAll();
if (isset($users[0]) {
if (password_verify($_POST['password'], $users[0]->password) {
// valid login
} else {
// invalid password
}
} else {
// invalid username
}
Your code should be
$hash = md5( rand(0,1000) );
$stmt = $mysqli->prepare("INSERT INTO users (username, password, hash) VALUES (?, ?, ?)");
$password = md5($password);
$stmt->bind_param('sss', $username, $password, $hash);
You don't need to escape with parameterized queries.
Issues you had, your escape function was incorrect you need the object with the function when using OO approach.
$mysqli->real_escape_string($hash);
would have been what you wanted.
You also were binding that value again though which would have thrown an error and didn't set it in the variable types being passed.
A string that contains one or more characters which specify the types for the corresponding bind variables.
So
$stmt->bind_param('ss', $username, $password, mysqli_escape_string($hash));
should have had three 's's because there are three strings, and no need for the escaping.
Also md5ing passwords isn't the best practice anymore, take a look at:
Secure hash and salt for PHP passwords
https://security.stackexchange.com/questions/19906/is-md5-considered-insecure
I can't figure out why the password isn't matching when attempting to login after activation. I've trimmed down the pasted code below for ease of viewing.
Here is the relevant registration code:
$salt = substr(sha1(uniqid(rand(),true)),0,20);
$password_db = hash('sha256', $salt.$password1);
$sqlinfo = mysql_query("INSERT INTO db_1 (email, password, salt)
VALUES('$email1','$password_db','$salt')") or die(mysql_error());
Here is the correlating code for login:
$email = $_POST['email'];
$password = $_POST['password'];
$sqlinfo = mysql_query("SELECT * FROM db_1 WHERE email='$email' AND emailactiv='1'");
if($sqlinfo['password'] == hash('sha256', $sqlinfo['salt'].$password)){
while($row = mysql_fetch_array($sqlinfo)){
... }
else { ...
I've done several iterations thus far to no avail. Any insight would be much appreciated.
you code, currently, is vulnerable with SQL injection. One suggestion is to reformat your code using PDO or MySQLI.
Example of PDO:
<?php
$stmt = $dbh->prepare("SELECT * FROM db_1 WHERE email = ? AND emailactiv=? ");
$stmt->bindParam(1, $email);
$stmt->bindParam(2, 1);
$stmt->execute();
?>
you didn't fetch the row that's why it's not matching anything.
add this line before the IF statement:
$rowHere = mysql_fetch_row($sqlinfo);
and use $rowHere in your IF statement.
$email = $_POST['email'];
$password = $_POST['password'];
$sqlinfo = mysql_query("SELECT * FROM db_1 WHERE email='$email' AND emailactiv='1'");
//You need to first fetch data before using it.
while($result = mysql_fetch_array($sqlinfo)) {
//Now you can use the data
if($result['password'] == hash('sha256', $result['salt'].$password)){
//matched... login correct
} else {
//not matched.. invalid login
}
}
...
Hope it's self-explanatory.
You missed one very important line!
BTW, stop using mysql_* functions as they are deprecated, use PDO or mysqli_*
EDIT: Please try now. I thought it can only hold one value (for login purpose)
You need to use mysqli_fetch_array.
Also, mysql_* functions are deprecated. Use MySQLi or PDO instead.
And you need to 'sanitize your inputs' (a common phrase) to avoid SQL injection, using mysqli_real_escape_string or PDO.
See the Bobby Tables link as per the comments on the question.