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.
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.
When I use prepared statements do I have to use functions like mysqli_real_escape_string or are the executed automatically?
For example should I just use this
$stmt = $mysqli->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam('sd', $name, $value);
or do I have to use something like this
$stmt = $mysqli->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam('sd', mysqli_real_escape_string($name), mysqli_real_escape_string($value));
Which functions are recommended to avoid sql injections?
No, you do not need to escape your parameters. In fact, escaping variables that you then pass in to a parametrized query is an error and will give you incorrect results.
When using parameterized queries, the escaping is done by the API. your first method is correct.
If you are doing raw text queries, then you should escape your parameter values.
Prepared statements automatically scrub what you're inserting. When you do the following:
$stmt = $mysqli->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
That bindParam function is doing all the necessary cleaning for you and then inserting that value into the query string.
Fun fact, prepared statements are a hack built on top of a hack in their fundamental idea :)
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
Two related questions that should be easy, though my searching has come up empty.
I have a from in PHP. If a field has a semi-colon in it, and I do a dump of $_POST in the action page, the field value is truncated at the semi-colon. I'm guessing this is related to SQL injection security? But legitimate semi-colons need to be allowed. Is there a setting that allows this to go through? Or do I need to escape it, and if so, how?
To catch actual SQL injections, I don't need to allow multiple statements in one query... like "SELECT * FROM table;DROP table". Is there a setting that disables this, either in PHP or MySQL, but without stopping legitimate semicolons?
semi-colons does not cause any problem.
Use prepared statements.
In mysqli:
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
In PDO:
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
Use mysql_real_escape_string
$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);
mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
Check this question for more information How can I prevent SQL injection in PHP?
Ok, silly me. Yes, I am using prepared statements, escaping, etc. But I also wanted to sanitize the input before it even gets that far. So I have a global function that checks all parameters, taking out anything following apostrophes and semicolons. Works fine for GET values, but I forgot that I needed to update that to handle POST parameters differently, and had forgotten this was there, as I hadn't type a semi-colon until now. :) But thanks for the responses.
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.