This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I have been using this code on my website for a long time, and just want to make sure I am correctly sanatizing my PHP $_POST inputs...
foreach($_POST as $key=>$val) //this code will sanitize your inputs.
$_POST[$key] = mysqli_real_escape_string($connection, $val);
Say for example I had the POST value $_POST['comment'] that I wanted to add to a database, would this be a good and safe way to sanatize it before database entry?
foreach($_POST as $key=>$val) //this code will sanitize your inputs.
$_POST[$key] = mysqli_real_escape_string($connection, $val);
//is this safe? or is there another step?
$comment = $_POST['comment'];
if($comment != ""){
//add $comment to database
}
Is there something that I still need to do before adding $comment to the MYSQL database? Or do those top two lines do the magic by themselves? Please let me know if this is a good safe way to do it, or if there is an even better way! Thanks!
Possible duplicate of: https://stackoverflow.com/questions/15664021/php-escaping-vars-posted-through-var-and-got-by-postvari-with-a-meth
I already tried your way. It seems there's no magic function. However, from classic MySQL injections, you can be safe, when adding mysqli_real_escape_string to each posted value, then use it as a string (quoted) in the db, but it's considered bad practice, also is not the most secure way
Since MySQLi presents parametised queries, you should get familiar with them, and leave the real corresponding to the database driver, to the library.
It's not. One can use multibyte attacks, which will bypass all these sanitizers.
Moreover,
According to this answer one should avoid writing to post so one can keep sanitized code far from un-sanitized. Even though you "sanitize" everything, it leads to bad habits.
This is not a good way to sanitize input. Queries should be parameterized and input should be fed as arguments no matter where it comes from. No additional sanitation should be done (otherwise it could be duplicated).
If you have specific rules (such as $comment != "") this is validation, and it is up to you to decide validation rules and how to handle invalid input (which is different than unsanitized input).
Example of using properly parameterized prepared statement with mysqli:
$stmt = mysqli_prepare($connection, "INSERT INTO comments VALUES (?)");
mysqli_stmt_bind_param($stmt "s", $comment);
mysqli_execute($stmt);
_real_escape_string does not sanitize user inputs completely. You must use prepared statements.
Object oriented style
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
Procedural style
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
Parameter types
Character Description
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
Documentation
down side is that you maim the post vars so you cant use them for other purposes than queries. for example what if you still wanted to echo out some post vars?
better is to escape to a new array
and even better is to not escaped but use parameterized queries.
Your missing some of the most important things to safe PHP coding.
Lets start from the beginning.
Start with these links please : Please read the code comments
This first // and this second!
1) Validate and then filter your data if it passes validation!
So we have a registration form, one that takes emails... so now what we do is validate the email.
$email = $_POST['email']; // Declare the variable
if (filter_var($email, FILTER_VALIDATE_EMAIL)) { // If validation passes ...
$safe_email = filter_var($email, FILTER_SANITIZE_EMAIL) // Sanitize the email
} else { // Validation fails no need to sanitize
echo "WRONG EMAIL PUNK!!!!";
}
2) Now using either Mysqli or PDO (I prefer PDO) we do :
$dbh = new PDO("mysql:host=xxxxxx;dbname=xxxxxx;charset=utf8", USERNAME(XXXXXXXXX), PASSWORD(XXXXXXXX); // Set up the PDO instance PLEASE DO NOT FORGET TO EXPLICETELY STATE A CHARSET!!!!
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set up error mode
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); // I prefer emulate prepares to be false
$sql = INSERT INTO ..... (........., email) VALUES (............, :email); // Set up our named parameter
$query -> $dbh -> prepare($sql); // Prepare the query
$query -> bindParam (':email', $email);
$query -> execute() // Yay!
Its all fine and dandy using PDO and MysqlI but there is an expression called :
Its not the wand, its the wizard.
PDO / MysqlI can not solve everything! Make sure to
Refer to my other question on how to set up PDO
1) Validate
2) Sanitize
3) use parameters for safer queries!
4) Escape any outside (un-trusted data)
Follow these security PHP practices for safer php coding.
Enjoy
Related
I have some form data that I'm writing to a database with PDO prepared statements.
This form data is santized and validated on the on the way in to the database with filter_var() functions and regular expressions and when any of this data is outputted to the site it escaped with htmlspecialchars().
To prevent SQL injections I'm using I'm using the code below. When I first learnt PDO this was what I saw in the tutorial and I personally find it very easy to read/understand.
I've noticed on the php.net site and in some other code I've saw recently they used bindparams(), whereas in the code below I've always done this inside an array in the execute() method.
Is my code below secure? Or must I use bindparams in the way that is shown in the second code example?
Here is some sample code using a firstname input from a webform
<?php
$firstname = $_POST['firstname'];
$firstname = filter_var($fname, FILTER_SANITIZE_STRING);
if(empty(trim($fname))){
$error[] = "First Name cannot be blank";
}
$sql = "INSERT INTO users (firstname) VALUES (:firstname)";
$stmt = $connection->prepare($sql);
$stmt->execute([
':firstname' => $firstname,
]);
In the php.net docs it does the above prepared statement using bindParam(), which seems a little verbose if you are updating a number of fields?
<?php
$sql = "INSERT INTO users (firstname) VALUES (:firstname)";
$stmt = $connection->prepare($sql);
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->execute();
If it is more secure then I'll obviously have to do it the second way, but wanted to check if my prepared statements given in the first code block are secure ?
It's fine either way. The security benefit is from using placeholders at all. There are some cases (dynamically constructed queries) where it's beneficial to use bindParam separately from the execute call, and there are others where you would prefer to avoid the verbosity. Use what suits you.
I'm currently setting up php scripts for my app and I'm abit clueless about how to obtain a level of safety to prevent injections to the sql server.
there are a few scripts that receive input from the app and not from the user directly such as content browsing and content rating, altho it is eventually an input.
the script that does receive user direct input as "name" and "creator name" is this :
$utc_str = gmdate("M d Y H:i:s", time());
$TIMESTAMP = strtotime($utc_str);
$DATA = $_POST['DATA'];
$NAME = $_POST['NAME'];
$CREATOR = $_POST['CREATOR'];
if(strlen($NAME) > 15 || strlen($CREATOR) > 15) exit("Error 2");
$stmt = $connect->prepare("INSERT INTO `ugcl` (`DATA`,`NAME`,`CREATOR`,`CREATEDSTAMP`)
VALUES (?, ?, ?, ". $TIMESTAMP .")");
$stmt->bind_param("sss", $DATA, $NAME, $CREATOR);
if($stmt->execute())
{
echo "Successs";
}
else
{
echo "Error";
}
should i use bind params in all of the scripts that receive input?
is there any thing else that is recommended?
Yes you should use PREPARED STATEMENTS in php whenever making an input or output.
Always bind the parameters so that the server always knows what datatype to expect. This will make sure you've an added security to your application. Everything you enter should be used as a ? in the original statement and bind the variables with the appropriate datatypes.
You're directly entering the $TIMESTAMP which I won't personally recommend either. Running that through a bind_param wont take much effort.
Also, always close your connections with a $stmt->close() and $conn->close() once a query statement is completed. If you have multiple queries in a page, start the connection at the beginning of the queries and end it after all the queries are done.
Also, another note on security- always validate and sanitize user inputs first. Never trust user data. Never take them to be valid in the first place.
Edit: Also consider using PDO for database interaction.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
I need some help and very very fast because my database was injected. I need at least a script that won't allow users to use :[Spaces, Sybols like ('*','=','/','.') and a list of words ('SELECT','FROM','WHERE')] in the text fields of my register form.
I heared something about mysql_real_escape_string(). What is this command doing? And don't post links to PHP: mysql_real_escape_string() Manual because I already read that.
There'a a right and a wrong way to approach this. The (usually) wrong way is to try and set up an input sanitation method (like a script) and hope that nothing gets through. It usually doesn't work.
What I recommend you to do is rewrite your PHP SQL queries to use MySQLi prepared statements. These are queries that are first converted from the common SQL syntax ("SELECT... WHERE...") to a statement your engine can work with, and only then are the fields replaced with your input, thus preventing SQL injection.
For example, the (very) susceptible SQL syntax:
"SELECT * FROM users_passwords WHERE user='" + user + "' AND pass='" + password + "'"
Can be converted to the following prepared statement:
"SELECT * FROM users_passwords WHERE user=? AND password=?"
And then, using the command bind_param(), you can safely replace the ? placeholders with your parameters after the statement is prepared. While the original SQL query allows you to use some basic injection techniques (like writing ' OR true OR '), prepared statements will not allow this.
Here's a working example:
// Create a new MySQLi connection object
$db = new mysqli('localhost','db_username','db_password','db_name');
// Create a new prepared statement
$stmt = $db->prepare('SELECT * FROM users_passwords WHERE user=? AND pass=?');
// Bind the parameters, in order, to the statement (s stands for string)
$stmt->bind_param('ss', username, password);
// Self-explanatory
$stmt->execute();
If you are in PHP then why don't you do it in your PHP script. sanitize all your user provided input in GET and POST and then move it forward to DB calls. That is the right way to do it.
I would strongly avoid constructing SQL query strings from any input even if you sanitize it.
The good way for security purposes and performance is to use functions to set the parameters:
for example:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
see 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.
I am a newbie, just to be clear. I hear a lot about escaping data to prevent XSS attacks. How do I actually do that?
This is what I am doing currently -
$s = mysqli_real_escape_string($connect,$_POST['name']));
Is this enough? Thanks
If you output the data to html you should use htmlspecialchars()
else, if you're storing the data in a database you should escape strings using mysqli_real_escape_string() and cast numbers (or use prepared statements for both)
and protect identifiers/operators by whitelist-based filtering whem.
Both these methods are all you need if you use them the correct way.
You should use htmlspecialchars for output rather than mysqli_real_escape_string.
If you are just starting to fix your code against attacks (meaning SQL Injection attacks), you will be better of checking out parameterized queries. What you basically do with these is separate your content (input) from the commands (sql), so you can never have them confused by a possible mallicious user-entered piece of information like the name.
You can try starting with using the PDO class:
You can start reading the PDO manual here: http://php.net/manual/en/book.pdo.php and this page has a nice example: http://php.net/manual/en/pdo.prepared-statements.php
<?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();
?>
However, you don't need to use PDO, you can use mysqli also, see http://php.net/manual/en/mysqli.prepare.php
<?php
/* Script A -- We are already connected to the database */
$stmt = mysqli_prepare($link, "INSERT INTO table VALUES (?, ?, 100)"); /* Query 1 */
mysqli_stmt_bind_param($stmt, "si", $string, $integer);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt); // CLOSE $stmt
?>
Because the name is a separate value, it can never be an SQL command, so you will be safe automatically.