My application currently applies if (get_magic_quotes_gpc()) { stripslashes } followed by mysqli_real_escape_string() to all strings, confirms email and URL formats with filters and confirms all integer and image data types before using them in a query.
I've mastered the basics of applying prepared statements with parameters, e.g.,
$query = "INSERT INTO my_table (col1, col2, modified) VALUES (?,?, CURRENT_TIMESTAMP)";
$stmt = mysqli_prepare($connect, $query);
mysqli_stmt_bind_param($stmt, "ss", $string1, $string2);
if (!mysqli_stmt_execute($stmt)) {display error}
else {do something else}
When a string has an apostrophe (single quote), as in O'Grady, it is escaped with a backslash as O\'Grady when inserted. And every time a user updates the account the escape slashes increase exponentially. Is there a way to avoid this on INSERT and UPDATE; if not how can it be eliminated on SELECT so it doesn't display when retrieved (and multiply)?
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 am using mysqli prepared statement to insert values into the database. I know that this extension handles characters escaping properly.
I have a file path : images/serveover/Bellini 83.png, what I am expecting to see after insert is the file path with escaped characters in the database, something like images\/serveover\/Bellini 83.png but I only see the image path as is.
How can I make sure that my string has been properly escaped? Is this view standard in phpMyAdmin where It does not show escaped characters or is it just hiding them on view?
Below is my insert prepared statement with params where all the values are being filled properly :
$insertQuery = $conn -> prepare("INSERT INTO images (image_id, image_date_created, image_date_modified, image_title, image_src, category_id, image_status, image_external_file, another_id) VALUES (null, NOW(), CURRENT_TIMESTAMP, ?, ?, ?,'A', ?, ?)");
if($insertQuery )
{
$insertQuery -> bind_param("ssisi", $title, $image, $row["category_id"], $file, $row["id"]);
$insertQuery -> execute();
$insertQuery -> close();
}
As long as you're dealing with strings, the escaping process simply instructs MySQL to ignore the special properties of a character and treat it like a normal character.
Bob\'s special string
Is entered into the database as
Bob's special string
It's important to note that prepared statements don't use escaping at all. Prepared statements send the query in one set and the data in another, so MySQL doesn't need to escape it, since it knows that's the actual value to store.
You can read more about the process in the MySQL manual
https://dev.mysql.com/doc/refman/5.0/en/string-literals.html
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();
}
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 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.