How to secure SQL query from input?
I am posting parameter to a page in php & then I have to insert it into database but I don't know how to secure the input parameter
<?php
$con=mysqli_connect("example.com","peter","abc123","my_db");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
mysqli_query($con,"INSERT INTO Persons (FirstName, LastName, Age)
VALUES ($_POST['FirstName'], $_POST['LastName'],$_POST['Age'])");
mysqli_close($con);
?>
You can easily do this with the mysqli set of functions by escaping those strings beforehand. The MySQL PHP drivers contains a function to safely escape strings for insertion into a string -> mysqli_real_escape_string.
That would change your query to:
mysqli_query($con,"INSERT INTO Persons (FirstName, LastName, Age) VALUES ('" . mysqli_real_escape_string($_POST['FirstName']) . "', '" . mysqli_real_escape_string($_POST['LastName']) . "', '" . mysqli_real_escape_string($_POST['Age']) . "')");
This will handle the majority of your concerns with securing input for SQL.
Optionally
Take full advantage of the driver escaping for other types and safer queries by using prepared statements, which you can also do with mysqli like:
// Prepare our query
$stmt = mysqli_prepare($con, "INSERT INTO Persons (FirstName, LastName, Age) VALUES (?, ?, ?)");
// Bind params to statement
mysqli_stmt_bind_param($stmt, "ssi", $_POST["FirstName"], $_POST["LastName"], $_POST["Age"]);
// Execute the query
mysqli_stmt_execute($stmt);
You will need to do multiple things. First of all, why are you using the usual MYSQL methods? You should use PDO objects. http://php.net/manual/en/book.pdo.php
Then you can use the prepare() method and then insert it as an array.
Please check http://php.net/manual/en/pdo.prepared-statements.php
the best thing for you to do is to use a framework like CodeIgniter, Kohana, Zend ...
that already has secure classes built in.
if you dont want to use the frameworks you can just take these classes.
another way, you can use ORM's.
you can use redbean
http://www.redbeanphp.com/
the best and easiest ORM i have ever used
Related
This question already has answers here:
How to use mysqli prepared statements?
(3 answers)
Closed 11 months ago.
I struggle to understand prepared statements in PHP to allow users to edit a MySQL-database.
The user input is UTF-8, typical examples are the name in Arabic, Chinese, ... It also generates a problem when using Geo-location as 47°23'15"N, 4°12°27"E, as is visible i.e. in Wikipedia.
Best lead I found to my problem to insert, insert ignore, on duplicate key ... to update datasets in a database from user-input using prepared statements. An interesting lead is in PHP Insert Prepared Statement, but that's "PDO", which I happen to lack any experience with.
So far I tried to sanitize, now it seems to me that it might be far easier and safer to use prepared statements. But. I'm bloody amateur. And use procedural statements. And never tried a prepared statement before. And the input expects better understanding.
So I would like to take something like
<?php
$name = $_POST['name'];
$user = filter_var($_POST['user'], FILTER_SANITIZE_EMAIL);
$descr = $_POST['utf8text'];
$geo = $_POST['geo']; // See [1] below.
?>
[1] Which is i.e. 47°23'15"N, 4°12'27"E and I am not sure how to properly escape it? filter_var($_POST['geo'],FILTER_SANITIZE_ADD_SLASHES) returns 47°23\'15\"N, 4°12\'27\"E?
Then to enter this into an SQL database like traditional
<?php
$link = mysqli_connect('localhost', 'user', 'pass','database');
mysqli_set_charset($link,'utf8');
$insertsql = "INSERT INTO `database` (`name`,`user`,`descr`, geo)
VALUES ('". $name . "', '" . $user . "', '" . $descr . "', " . $geo . "')
ON DUPLICATE KEY UPDATE `descr`='" . $descr . "', '" . $geo . "';
mysqli_query($link,$insertsql);
?>
Okayokay, using added code to make sure the database connection works, the query is processed properly and failure handling. But I want to simplify.
My question would be, how I would prepare such group of values for a prepared statement. And I believe to understand I must replace mysqli_query with mysqli_prepare and I need a count of the fields addressed and use "ssss" but don't find any explanation in any of the manuals what the s's (multiple "s") do.
What I tried didn't work (yet) and I need a working example to understand what I have to do. I tried to adjust the example in above linked article without PDO to no success.
And I am worried if/how the prepared data is transferred in strings when using ON DUPLICATE KEY, as I don't find any explanation there either (PEBKAS?).
Any help appreciated!
If I understood correctly, you want to make a mysql prepared query?
(I apologize if I misunderstood the problem)
But here my solution and explanation. First :
$stmt = mysqli_prepare($link, "INSERT INTO `database` (`name`,`user`,`descr`, geo) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE descr= ?, ?;");
Here $link is your mysqli_connect
You set ? where you want to put your future variables
mysqli_stmt_bind_param($stmt, 'ssssss', $name, $user, $descr, $geo, $descr, $geo);
All ? need to be defenied what types of variable it's gonna be, here it's gonna be a string so we set S (You can find the others possibilities for the second parameter here)
Then all ? will be bound to your variables in the order in which you want it to appear instead of ?
mysqli_stmt_execute($stmt)
And finally you execute the query
I am trying to avoid SQL injection in my page.
// Connect to database server and select database
$connection = new PDO("mysql:dbname=tt8888;host=mysql.tt8888.com", "tt8888", "ttnopassword");
// Quote data to prevent SQL injection
$name = $connection->quote($name);
// Insert now
$connection->query("INSERT INTO Contact (name, eeeee, llll, mmmmm, iiiii) VALUES ('$name','$eeeee','$llll','$mmmmm','$iiiii');");
Without quote(), it inserts just fine. And using print $name;, the quote() part seems work fine. Why is there nothing inserted into database after using quote()?
PDO::quote will put single quotes around your values. So you don't need to do that yourself in your SQL.
Though I'd strongly recommend you switch to using prepare() with named parameters.
Do not use PDO::quote. It is much better to use parameterized queries.
$stmt = $connection->prepare("INSERT INTO Contact (name, e, l, m, i) VALUES (?,
?, ?, ?, ?)");
// This will quote all of the values for you
$stmt->execute(array($name, $eeeee, $llll, $mmmm, $iiiii));
You can also use bind methods (bindParam or bindValue) instead of passing the arguments directly to execute. This will allow you to specify the data types if it's necessary, but it seems like these are all supposed to be strings.
I am trying to store some form data to a SQL database using the following query:
$sql = "INSERT INTO attendees (first_name, surname, partner, phone) VALUES ($first_name, $surname, $partner, $phone)";
It works perfectly if I hard code the values to test it, but when using these variables, it breaks and gives me Error 1054
$first_name = $_POST['first_name'];
$surname = $_POST['surname'];
$partner = $_POST['partner'];
$phone = $_POST['phone'];
Could anyone help?
$sql = "INSERT INTO attendees (first_name, surname, partner, phone) VALUES ($first_name, $surname, $partner, $phone)";
should be
$sql = "INSERT INTO attendees (first_name, surname, partner, phone) VALUES ('$first_name', '$surname', '$partner', '$phone')";
you are missing quotes around field content.
Warning: your code is vulnerable to SQL injection attacks
try to use PHP Prepared statement and wiki page http://en.wikipedia.org/wiki/Prepared_statement . Or at-least use mysqli_real_escape_string
Err 1054 means that you are using a column name that doesn't exist.
In this case, as there doesn't seem to be anything wrong with your insert statement (assuming that all the variables have data in them) it means you have likely typo'ed a column name.
On second thoughts, you probably need single quotes around the strings, but the first part of my answer still stands.
First of all, stop using mysql_ functions and look for PDO and prepared statements: if you'll do as suggested, this problem will sort by itself.
Anyway, the problem is that the query will replace the values with the strings contained in your $_POST array... but without string delimiters.
This means that mysql will look at them as column names, and spaces will break them!
solution:
$sql = "INSERT INTO attendees (first_name, surname, partner, phone) VALUES ('$first_name', '$surname', '$partner', '$phone')";
NOTICE that this will leave you wide open to SQL injection attacks!
with PDO it'll look something similar to this:
$stmt = $db->prepare("INSERT INTO attendees (first_name, surname, partner, phone) VALUES (:fname, :sname, :partn, :phone)");
$stmt->execute(array(':fname' => $first_name, ':sname' => $surname_name, [the others]))
which will is much more secure and plainly better all around.
Please escape and verify your inputs, otherwise you'll be vulnerable to SQL injections.
Here's a list of good solutions on how to do that: http://bobby-tables.com/php.html
Basically try to use prepared statements if possible, otherwise use mysql_real_escape_string()
I have an error with my insert into line, it's about this bad boy
mysql_query("INSERT INTO accounts('username', 'password', 'firstname', 'lastname', 'email')
VALUES($username, $password, $firstname, $lastname, $email)")
or die("Could not create account! <br/>" . mysql_error());
the error I am supplied with is the following:
Could not create account!
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''username', 'password', 'firstname', 'lastname', 'email') VALUES(test, test,' at line 1
I suspect it has something to do with the variables not being called correctly?
There are a variety of problems, so I'll summarize them:
INSERT INTO t1 ('col' -- note that 'col' is wrapped in quotes. This means that it attempts to insert into the string literal "col1" rather than the column name. Remove the quotes and replace them with backticks (or nothing)
The values themselves are not wrapped in quotes. You have VALUES(test -- this semantically means insert the value of column "test," which makes no sense. You actually need to wrap this one in quotes.
I'd venture to guess that none of the input parameters are properly escaped. You should use properly parameterized queries with PDO or mysqli.
My friend the fields in the querys shouldn't be quoted. Try this:
mysql_query("INSERT INTO accounts (username, password, firstname, lastname, email) VALUES($username, $password, $firstname, $lastname, $email)") or die("Could not create account!" . mysql_error());
Good luck
you don't have to use quotes ' in the query but backtick `
mysql_query("INSERT INTO `accounts` (`username`, `password`, `firstname`, `lastname`, `email`) VALUES('".$username."', '".$password."','". $firstname."', '".$lastname."', '".$email."')") or die("Could not create account! " . mysql_error())
insert into documentation
I would like to also to remember you that mysql_ functions are deprecated so i would advise you to switch to mysqli or PDO for new projects.
mysql_query is not recommended, soon to be deprecated. Probably best to use PDO or mysqli instead.
http://php.net/manual/en/function.mysql-query.php
But to answer your question, I believe it's because your column names are in single quotes(rather than backticks).
It's your values that need to be within single-quotes. You'll probably want to run mysql_real_escape_string on those variables too, to prevent SQL injection. Or just use PDO prepared statements instead.
http://php.net/manual/en/pdo.prepared-statements.php
I am starting a very basic site that uses a single line form to post into a database and then later echo that $comment variable on the page. I don't know PDO, but am willing to learn if I truly need it for something this simple.
else
mysql_query("INSERT INTO posts (postid, post_content)
VALUES ('', '$comment <br />')");
}
mysql_close($con);
Above this code I have basic strpos commands to block out some of the things I don't want posted.
Am I going to experience any issues with injections down the road from how I am doing this?
No, it's not safe, you need to use mysql_real_escape_string to escape $comment.
But, PDO is nothing difficult and make your code stronger.
// create the connection. something like mysql_connect/mysql_error
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
// create the prepared statement.
$stmt = $dbh->prepare("INSERT INTO posts (postid, post_content) VALUES (?, ?)");
// execute it with parameters.
$stmt->execute(array('', $comment.'<br>'));
Yes this is dangerous. All someone has to do is put a single quote then the SQL code they want after. Use $comment = mysql_real_escape_string($comment) before this statement if you want to fix it the old way or use PDO prepared statements as the newer way. Here is a basic example from the documentation:
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
This is susceptible to sql injection as your $comment is input from the user they may as well enter some SQL command and your PHP code will end up executing the same.
Consider $comment value is set to 'TRUNCATE TABLE USERS;' the USERS table could be anything which might be critical for your app.
In PHP I believe you safeguard against sql injection by using mysql_real_escape_string(). Read up on it.
Refer this doc for details abt SQL innjection: https://docs.google.com/document/d/1rO_LCBKJY0puvRhPhAfTD2iNVPfR4e9KiKDpDE2enMI/edit?pli=1
Binding form input data to mysql query is the perfect solution to the sql injection. Use binaParam method for this purpose.
No, judging only by the code you’ve posted here, you are not protected against SQL injections. Here’s a simple example for $comment:
'), (null, (select concat(user(),':',password) s from mysql.user where concat(user,'#',host)=user() LIMIT 1) --
This will add another row containing the login credentials of the current user. With LOAD_FILE he could also be able to read files from your file system. He could also write arbitrary files on the file system:
' + (select '<?php echo "Hello, World!";' into dumpfile '/path/to/your/document_root/foobar.php')) --
With this technique the attacker could upload arbitrary files to your server, e. g. a web shell to run arbitrary commands on your system.
So you definitely must protect yourself against SQL injections whereby automatic escaping using prepared statements or parameterized statements is favored over manual escaping using functions like mysql_real_escape_string.