I have this php pdo:
try {
$STH = $db->prepare("INSERT INTO racuni (napomene) VALUES (:12)");
$STH->bindParam(':12', $_POST['napomena'], PDO::PARAM_STR);
} catch (PDOException $e) {
echo $e->getMessage();
}
and now when I try to add this data to mysql:
<script>alert('heheheheheheh')</script>
there is no string escapes? And in database I have the same data:<script>alert('heheheheheheh')</script>
SO,
What is the best, safe way to insert data to mysql using php pdo?
When retrieving values from the database, you need to treat those values as if they are unsafe, as if they might include HTML special characters, or might contain javascript.
To get that value displayed safely in a web page, you need to run that value through a proper escaping mechanism.
PHP provides the htmlentities function to do just that, replacing HTML special characters with suitable replacements. As an example:
$val = htmlentitites("<script>alert('heheheheheheh')</script>");
Would assign something like this to $val
<script>alert('heheheheheheh')</script>
(It might also replace some other characters.) But the end result is if you put that string out on a web page, what you are going to "see" displayed on the web page appears like the original string. That string won't be interpreted as javascript.
Bottom line, you can't assume that because a string is being returned from the database that it's "safe". You must treat it as potentially unsafe.
Does PDO "sanitize" input?
In a word, NO. PDO doesn't sanitize values in SQL statements to remove HTML special characters or other potentially unsafe values.
What the prepared statement with the bind placeholder does is ensure that the value supplied in the statement gets passed into the database, without being interpreted as SQL text.
As an example, using PDO prepared statement with bind placeholder
$sql='INSERT INTO tab (col) VALUES (:val)';
$sth=$db->prepare($sql);
$sth->bindParam(':val', $value);
$sth->execute();
vs. incorporating the value into the SQL statement
$sql = "INSERT INTO tab (col) VALUES ('" ,. $value ."')";
$db->query($sql);
Consider what happens in each case when $value contains this string
foo'); DROP TABLE tab; --
With the first pattern (prepared statement with bind placeholder), that string value gets passed to the database, and stored in the column.
In the second example, incorporating that value into the text of the SQL statement, we get potentially dangerous SQL statements submitted:
INSERT INTO tab (col) VALUES ('foo'); DROP TABLE tab; --')
This an example of what SQL Injection vulnerability is about. And this demonstrates why using prepared statements with bind placeholders thwarts SQL Injection, it defends against a whole swath of nastiness that can happen when we don't treat values as potentially unsafe.
If $value contains the string:
<script>alert('heheheheheheh')</script>
With the prepared statement and bind placeholder, that's the value that's going to be stored in the database. It's just a string. It won't be interpreted as part of the SQL statement.
We can get the same thing to happen with the other pattern, that's vulnerable to SQL Injection, if we use double quotes instead of single quotes around the string literal in our SQL, e.g.
INSERT INTO tab (col) VALUES ("<script>alert('heheheheheheh')</script>")
Or, if we used an "escape string" function
INSERT INTO tab (col) VALUES ('<script>alert(''heheheheheheh'')</script>')
Again, that string gets stored in the database, because it's a valid string. It doesn't matter one whit whether that's got HTML special characters in it.
Bottom line, PDO does not sanitize HTML characters in strings. Your code needs to handle all values returned from the database as if they are potentially unsafe, and run them through the htmlentities or a similar function to "disarm" the values from being interpreted e.g. as javascript.
Using prepared statements is best, which is what you're doing (assuming you're executing the statement (not in your code sample)). Prepared statements escape values to prevent SQL injection, not cross-site scripting.
The value is unchanged entering the database, which is good (IMO). You should filter the values when you output them if needed (for example, htmlentities()).
You can also bind params in the execute method:
$STH = $db->prepare("INSERT INTO racuni (napomene) VALUES (?)");
$STH->execute(array($_POST['napomena']));
First you need to tell PDO to throw exceptions as bellow:
$pdo = new PDO("mysql:host={$dbhost};dbname={$dbname}", $dbuser, $dbpass);
// add this:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now wrap your database operations in a try - catch block:
try
{
$statement = $pdo->prepare("INSERT INTO racuni (napomene) VALUES (:12)");
$statement->bindParam(':12', $_POST['napomena'], PDO::PARAM_STR);
// etc.
$statement->execute();
}
catch ( PDOException $exception )
{
echo "PDO error :" . $exception->getMessage();
}
Related
Hello i'm a beginner so please at least try to give me a hint,a example.
English isn't my main language so please endure it.
If somebody type " Hello my name is J'hon ' the text don't insert in database, but if he type 'Hello my name is jhon' it does. I think it is something about '
Ok so i'm having the problem that if someone types
'Hello my name is J[color=#FF0000]'[/color]hon J'onz. ' is not inserted in the database..
This is the script:
mysqli_query($DB_H, "INSERT INTO tickets (name, continutscurt, continut,type,status) VALUES ('".$_SESSION['username']."', '".$_POST['titlu']."', '".$_POST['continut']."', $numar, 0)");
You should really use prepared statements when dealing with any kind of user-input. If you for any weird reason isn't using prepared statements, take a look at the function mysqli::real_escape_string. This will deal with special characters, such as ', which may break the SQL.
With using prepared statements, your code would look like
if ($stmt = $DB_H->prepare("INSERT INTO tickets (`name`, continutscurt, continut, `type`, `status`) VALUES (?, ?, ?, ?, ?)")) {
$stmt->bind_param("ssssi", $_SESSION['username'], $_POST['titlu'], $_POST['continut'], $numar, 0);
$stmt->execute();
$stmt->close();
} else {
echo mysqli_error($DB_H);
}
If you however want to use mysqli::real_escape_string, you'll need to bind the SESSIONs and POSTs to a variable where in you insert instead, like this (you can also do it directly in the query, but this makes for cleaner code).
$username = mysqli_real_escape_string ($DB_H, $_SESSION['username']);
$titlu = mysqli_real_escape_string ($DB_H, $_POST['titlu']);
$continut = mysqli_real_escape_string ($DB_H, $_POST['continut']);
$numar = mysqli_real_escape_string ($DB_H, $numar);
if (!mysqli_query($DB_H, "INSERT INTO tickets (`name`, continutscurt, continut, `type`, `status`) VALUES ('$username', '$titlu', '$continut', '$numar', 0")) {
echo mysqli_error($DB_H);
}
I also put backticks ` around name, status and type, as these are keywords in SQL. This isn't strictly necessary, but it's good practice with words that are listed as either reserved words or keywords, more info on this list of keywords.
You shouldn't take for granted that your queries are successful, so I added an if-block around them. Errors shouldn't be displayed unless in production/development.
References:
http://php.net/manual/en/mysqli.real-escape-string.php
http://php.net/manual/en/mysqli.prepare.php
How can I prevent SQL injection in PHP?
https://dev.mysql.com/doc/refman/5.7/en/keywords.html
The issue is SQL Injection.
You have potentially unsafe values being included within the SQL text.
To see this, break up the code a little bit.
$sql = "INSERT INTO tickets ...'" . $val . "' ... ";
echo $sql;
The echo is there just as a way to see what's going on, for you to examine the contents of the string containing the SQL text. And then take that string over to another client, and test it. And you will see what the the problem is.
... VALUES ( ..., 'J'onz. ', ...
isn't valid. That single quote is ending the string, so the string is just 'J', and the next part, MySQL is going to try to interpret as part of the SQL, not the string value. (This is a nefarious vulnerability. Cleverly constructed strings and wreak havoc on your application and your database.)
One approach to fixing that is to sanitize the values, so they can be safely included.
... VALUES ( ..., 'J\'onz. ', ...
^^
... VALUES ( ..., 'J''onz. ', ...
^^
As a simple demonstration try these queries:
SELECT 'J\'onz. '
SELECT 'J''onz. '
SELECT 'J'onz. '
(The first two will return the string you expect, and the third will cause an error.)
The take away is that potentially unsafe values that are going to included in the text of a SQL statement need to be properly escaped. Fortunately, the MySQL client library includes mysqli_real_escape_string function. Variables that may potentially contain a single quote character can be run through that function, and the return from the function can be included in the SQL text.
$sql = "INSERT INTO tickets ...'"
. mysqli_real_escape_string($DB_H,$val)
. "' ... ";
Again, echo out the $sql and you can see that a single quote has been escaped, either by preceding it with a backslash character, or replacing it with two sinqle quotes.
There's a much better pattern than "escaping" strings. And that's to use prepared statements with bind placeholders.
The SQL text can be a static string:
$sql = 'INSERT INTO mytable (mycol) VALUES ( ? )'
And then you msyqli_prepare the statement.
And then supply values for the placeholders with a call to mysqli_bind_param.
And then call mysqli_execute.
With this pattern, we don't need to mess with running the "escape string" function to sanitize the inputs.
I was reading lots of forums and answers on Stack over flow regarding SQL-Injection
and i came to know this is very basic level of SQL-injection
$_POST['name'] = 'xyz;DROP Table users';
mysqli_query ('select * from abc where name='."$_POST['name']")
To prevent this
Use mysqli_escape_stirng on any input that comes from user can save me from SQl-injection
Use PDO and prepare statement can also save me from SQL-injection
Q1. What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
Q2. How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
Any help in this regard his highly appreciated
The problem with incorporating user input into SQL is that in the resulting SQL you can’t tell which parts were provided by the developer and which by the user. That’s why the developer must ensure that user input gets interpreted as intended.
This is where string escaping functions and parameterization come in:
String escaping functions like mysqli_real_escape_string process the value so that it can be securely used in a string literal without fearing it may be interpreted as anything else than string data.
However, it is important to note that the value is actually placed in a string literal and nowhere else as it’s only intended for that specific purpose, i. e., it ensures that the passed data is interpreted as string data only when placed inside a string literal. Unfortunately, the PHP manual fails to mention the string literal part.
Parameterization as implemented by prepared statements separate the SQL and the data parameters. So there can’t be a confusion of SQL code and provided data. With server-side prepared statements first the statement gets prepared having only parameter placeholders and then the parameter values get passed for execution. And whenever a parameter is encountered, the DBMS uses the corresponding parameter value.
As for your specific example:
What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
It doesn’t because you didn’t put the value in a string literal. However, the following would work:
mysqli_query("select * from abc where name='$safe_variable'")
How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
As already said, you explicitly state what the SQL looks like by preparing the statement. And then you pass the parameters for execution. As the parameterized SQL and its parameters are separated, they won’t mix and a passed parameter value can’t be mistaken as SQL.
Q1:
mysql(i)_real_escape_string() calls MySQL's library function
mysql(i)_real_escape_string, which prepends backslashes to the following
characters: \x00, \n, \r, \, ', " and \x1a.
(http://php.net/mysqli_real_escape_string)
Note that this depends on the character encoding (not workin in this case is SET NAMES ... (security risk!!!), $mysqli->set_charset('utf8'); should be used!). (You can read about encoding in my post Mastering UTF-8 encoding in PHP and MySQL.)
How does it prevent SQL injection?
- Well it prevents breaking the variables context by escaping ' etc, the thing is, that mysql_query and mysqli_query only execute one query per query, that means, it simply ignores ;DROP Table users.
mysqli_real_escape_string DOES NOT prevent inserting code like DROP DATABASE.
Only PDO and/or mysqli_multi_query are vulnerable in this case.
Q2:
The statement is sent to the server first, then the bound variables will get sent seperated and then the statement gets executed, in this case, the security is provided by the database library, not by the client library. You should prefere this.
That means, you first send $dbh->prepare("select * from ABC where name = :name"); to the server and the database knows your bind param will be inserted into the :name placeholder and it will automatically wrap it properly to not break out of its supposed context. The database will try to look for a name value of xyz;DROP Table users and it won't executed any command, just fill that variable space.
I think this is the case for most SQL escaping functions:
They escape the control chars like ;, ', ", ...
So your string
xyz;DROP Table users
Will be escaped by the functions to
xyz\;DROP Table users
So your string now isn't a valid SQL command anymore.
But be aware of HTML tags in the data stored in a DB.
If I insert for example
<script>alert('foobar');</script>
This will be stored in DB and not treated by the SQL escape functions. If you print out the field somewhere again, the JS will be executed by the visitors browser.
So use in addtion htmlspecialchars() or htmlentities() for sanitize user input. This is also true for prepared statements.
I'm having troubles with an insert query with MySQL. Here's what I want to do:
in one of the fields in my table, I want to insert a bunch of URLs and their respective titles. I build up this query like so:
?content=<title of webpage>%%<url of webpage>%%<title of webpage>%%<url of webpage>%%
and so on, depending how many URLs there are.
The problem is if the URL contains something like "?var=somevalue" then my query breaks there since MySQL will think that I am declaring a new variable.
How can I achieve this?
I think that you should escape the sequence with a \
If you are using PHP an option is to use the following command (it has multiple forms):
Procedural style
string mysqli_real_escape_string ( mysqli $link , string $escapestr )
Object oriented style
string mysqli::escape_string ( string $escapestr )
string mysqli::real_escape_string ( string $escapestr )
Here is how to use placeholders in PHP (which I suspect is the language you're using)
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
$name = 'one';
$value = 1;
$stmt->execute();
I grabbed that from php.net
Placeholders, using prepared statements serve several functions, but one of them is to separate data from code safely so that the problem you're describing goes away.
Quoting from the site mentioned above:
The parameters to prepared statements
don't need to be quoted; the driver
automatically handles this. If an
application exclusively uses prepared
statements, the developer can be sure
that no SQL injection will occur
(however, if other portions of the
query are being built up with
unescaped input, SQL injection is
still possible).
I'm in the process of building a site with CodeIgniter. This is the 1st site that I've built myself that interacts with a database. I'm using MySQL for this project. How can I tell if data needs to be escaped before saving it to the database?
I would advice you to accustom yourself to use prepared statements. Especially since you are new to working with databases. The sooner you start using these, the easier it becomes a second nature.
I, for instance, didn't know about prepared statements when I started with databases. And I experienced my own stubborness when I came in touch with them. Because I had accustomed myself to another way of doing things already. Now, this might not be a character trade of yourself, but it doesn't hurt to start as soon as possible with it either way.
Prepared statements allow you to use placeholders in queries. These placeholders can then be substituted with actual values by binding them to the placeholders. This process of binding, automatically escapes the values.
Here's a (simple) PDO example:
$db = new PDO( /* some database parameters */ );
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
$statement->bindValue( ':username', $dirtyUsername );
$statement->bindValue( ':password', $dirtyPassword );
$result = $statement->execute();
// result checking ommited for brevity
There's lot's more possibilities with PDO and prepared statements. For instance you can easily reuse the prepared statement in a loop, as such:
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
foreach( $users as $dirtyUser )
{
$statement->bindValue( ':username', $dirtyUser->username );
$statement->bindValue( ':password', $dirtyUser->password );
$result = $statement->execute();
// result checking ommited for brevity
}
Or pass the placeholder bindings to the execute method, like so:
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
$result = $statement->execute( array(
':username' => $dirtyUsername,
':password' => $dirtyPassword
) );
// result checking ommited for brevity
... etc., etc.
Don't worry about escaping yourself (you WILL screw it up). Use a DB layer where you prepare the statement first, and then add data to it.
In PHP you should use PDO. You write
SELECT * FROM table WHERE key = :key AND value = :value
and then add the data in by calling functions.
If you're using the database class with query bindings, you don't have to do any manual escaping:
The secondary benefit of using binds
is that the values are automatically
escaped, producing safer queries. You
don't have to remember to manually
escape data; the engine does it
automatically for you.
If the data is a string, it must always be escaped.
However, it's better to use parameters instead.
If you are generating SQL yourself rather than using something like PDO, then you must always escape strings.
Escaping strings is a basic requirement of the SQL language. It's what allows you to use characters like apostrophes or backslashes in a string without everything going bad. There is no situation at all in which escaping strings is not required.
Even non-strings will have to be filtered to ensure that they are, indeed, non-strings.
If you are learning, please seriously consider learning something like PDO as many others have said, rather than escaping your own strings.
When in doubt, escape it all. Can't be too safe.
Alright, alright. I get it
ALWAYS ESCAPE
You escape a MySQL query string when any of the string is made up of user input, for example:
in PHP:
$username = ;//VALUE FROM USER INPUT
then your query string is:
"INSERT INTO table ('username') VALUES (".$username.")"
You would have to escape this mySQL query due to the fact the $username variable could potentionally have malicous code inserted by the client to be injected into your database.
When to escape? As soon as your site goes public.
I use mysql_real_escape_string() to validate all user inputs before I insert them in a sql database. One of the fields is name, and we've had issues with users with names like O'Reilly. Is there any way to use mysql_real_escape_string() to block injections but allow these names in the db?
The problem is most likely that the apostrophes get quoted twice: first by the evil and deprecated in 5.3 magic quotes and then by mysql_real_escape_string().
What you can do is either disable magic quotes or run stripslashes() on your input values before feeding them to mysql_real_escape_string()
Brief explanation of the problem:
the user enters O'Reilly
magic quotes automatically turn it into O\'Reilly
the script feeds the string through mysql_real_escape_string() which escapes both the backslash and the apostrophe (again) yielding O\\\'Reilly
the query is executed, the quoting is processed and the database understands that you want a backslash and an apostrophe since they where both escaped, and records O\'Reilly
As already mentionned : mysql_real_escape_string is not meant for input validation. If you want to validate inputs, use your own functions or the filter functions from php.
If you have too many slashes added automatically by php, disable magic quotes.
To prevent SQL injection, use parameterized queries with either PDO or mysqli.
+1 for using PDO. I've been using PDO in favour of a MySQL class acting as a database abstraction layer for a few months now and it's a breeze.
Traditionally, developers would use the stripslashes() function on data before applying a function like mysql_real_escape_string(). It's still a good idea to remove slashes from input data, but you can then either use the PDO method for escaping data (PDO::quote($data)) or binding the parameter.
Your query block would then look something like this:
$pdo = new PDO(DSN, DB_USER, DB_PASS);
$sql = "INSERT INTO table (field1, field2) VALUES (:value1, :value2)";
$smt = $pdo->prepare($sql);
$smt->bindParam(':value1', $value1, PDO::PARAM_STR);
$smt->bindParam(':value2', $value2, PDO::PARAM_STR);
$smt->execute();
$rows = $smt->rowCount(); // returns number of rows affected
I hope this helps somewhat. Take a look at http://php.net/manual/en/book.pdo.php for more information on PDO in PHP.