So using %27 you can just SQL inject even though data is sanitized with mysql_real_escape_string
%27) SQL INJECTION HERE %2F*
What to do?
Edit with example:
$sql = sprintf("SELECT *, MATCH(post) AGAINST ('%s*' IN BOOLEAN MODE) AS score FROM Posts WHERE MATCH(post) AGAINST('%s*' IN BOOLEAN MODE)",
mysql_real_escape_string($_GET['searchterm']),
mysql_real_escape_string($_GET['searchterm']));
$results = $db->queryAsArray($sql);
If you pass in %27) SQL INJECTION HERE %2F* to the searchterm querystring, I get outputted on the page:
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 'BOOLEAN
MODE)' at line 1
Thanks everyone for finding the problem in the db class..
Reasoning from the method name queryAsArray, it seems that you’re using this DbBase class from the comments of the MySQL functions manual page. If so, it’s the query method that removes the escape character from the escaped quotation marks:
function query($sql, &$records = null){
$sql = str_replace(array('\\"', "\\'"), array('"', "'"), $sql);
// …
}
Then it’s not a miracle that your example works (I simplified it):
$input = "', BAD SQL INJECTION --";
$sql = "SELECT '".mysql_real_escape_string($input)."'";
var_dump($sql); // string(33) "SELECT '\', BAD SQL INJECTION --'"
// everything’s OK ↑
$sql = str_replace(array('\\"', "\\'"), array('"', "'"), $sql);
var_dump($sql); // string(32) "SELECT '', BAD SQL INJECTION --'"
// Oops! ↑
The note mentioned in our manual has been marked for deletion. Once it propagates across all of the mirrors in our network, it will no longer appear attached to the official documentation.
~ Daniel P. Brown
Network Infrastructure Manager
http://php.net/
It's best to not to build statements like this at all, and instead use queries with parameters using mysqli or PDO. This will deal with the problem of MySQL injection and one day (not yet, unfortunately) it will perform better too, because the queries are cached without parameters, meaning you only got one query in the cache instead of dozens of different queries because of a single input value changing all the time. Other databases make use of this since long, but MySQL just managed not to make parameterized queries slower since the latest version.
It doesn't look plausible that %27 will actually terminate the string. It seems more like a possibility to embed quotes inside a string, but I'm not sure.
To be sure, I decided to sacrificed my server and test this. When I enter %27 in an input field and textarea that are escaped using mysql_real_escape_string and are then inserted in the database, I get no errors. The text %27 is just inserted. So no problem at all.
You are wrong. No injection possible here.
By following these three simple rules
Client's encoding properly set by mysql_set_charset()
Data being escaped using mysql_real_escape_string()
And enclosed in quotes
you can be sure that no injection possible
Related
I know most people say to just use prepared statements, but I have a site with many existent queries and I need to sanitize the variables by the mysqli_real_escape_string() function method.
Also the php manual of mysqli_query() says mysqli_real_escape_string() is an acceptable alternative, so here I am ...
I want to do this type of queries:
$query = sprintf("SELECT * FROM users WHERE user_name = %s",
query_var($user_name, "text"));
$Records = mysqli_query($db, $query) or die(mysqli_error($db));
I want to know below function would work, I am unsure if:
I should still do the stripslashes() at the start ? An old function I used from Adobe Dreamweaver did this.
Is it OK to add the quotes like $the_value = "'".$the_value."'"; after the mysqli_real_escape_string() ?
Does it have any obvious / big flaws ?
I noticed the stripslashes() removes multiple \\\\\\ and replaces it with one, so that migt not work well for general use, e.g when a user submits a text comment or an item description that might contain \\\\, is it generally OK not to use stripslashes() here ?
I am mostly worried about SQL injections, it is OK if submitted data included html tags and so, I deal with that when outputing / printing data.
if(!function_exists('query_var')){
function query_var($the_value, $the_type="text"){
global $db;
// do I still need this ?
// $the_value = stripslashes($the_value);
$the_value = mysqli_real_escape_string($db, $the_value);
// do not allow dummy type of variables
if(!in_array($the_type, array('text', 'int', 'float', 'double'))){
$the_type='text';
}
if($the_type=='text'){
$the_value = "'".$the_value."'";
}
if($the_type=='int'){
$the_value = intval($the_value);
}
if($the_type == 'float' or $the_type=='double'){
$the_value = floatval($the_value);
}
return $the_value;
}
}
A text string constant in MySQL / MariaDB starts and ends with a single quote ' character. If the text itself contains a quote character, we escape it by doubling it. So the name "O'Leary" looks like this in a SQL statement's text.
SET surname = 'O''Leary'
That's the only rule. If your users feed you data with backslashes or other escaping schemes, you can feed it verbatim to MySql with the kind of text string representation mentioned here.
Don't overthink this. But use carefully debugged escaping functions. Avoid writing your own, because any tiny bug will allow SQL injection.
Looking at the PHP functions documentation, I found some references that made me decide the stripslashes() is not needed in that function.
https://www.php.net/manual/en/security.database.sql-injection.php
Generic functions like addslashes() are useful only in a very specific
environment (e.g. MySQL in a single-byte character set with disabled
NO_BACKSLASH_ESCAPES) so it is better to avoid them.
https://www.php.net/manual/en/function.addslashes.php
The addslashes() is sometimes incorrectly used to try to prevent SQL
Injection. Instead, database-specific escaping functions and/or
prepared statements should be used.
I have read this:
will help you NOT against injection.
Beause escaping is just a string formatting facility, not injection preventer by any means.
Go figure.
However, escaping have something in common with prepared statements:
Them both doesn't guarantee you from injection if
you are using it only against notorious "user input", not as a strict rule for the building ANY query, despite of data source.
in case you need to insert not data but identifier or a keyword.
On the following Post: Are dynamic mysql queries with sql escaping just as secure as prepared statements?
So my question is that using:
$Var = "UserInput Data Possible SQL Injection";
$mysqli->real_escape_string($Var);
does not provide protection against SQL Injection?
I want to use $mysqli->query(); so I can use fetch_array(MYSQLI_ASSOC); Because to be frank, I have no idea how to fetch the results as an array after using a prepared statement.
So If I have this in my Database Connection:
$STD = new mysqli('localhost', 'root', 'xx', 'xx');
$STD->set_charset('utf8');
if ($STD->connect_error) {
die("Standard Access Has Been Revoked. Please Contact Administration");
}elseif (!$STD){
die ("Other problem With Connecting To Database, Please Contact Administration");
}
as stated in the manual for real_escape_string
http://php.net/manual/en/mysqli.real-escape-string.php
The above lists:
Caution
Security: the default character set
The character set must be set either at the server level, or with the API function mysqli_set_charset() for it to affect mysqli_real_escape_string(). See the concepts section on character sets for more information.
Which links to: http://php.net/manual/en/mysqli.set-charset.php
My overall question can split into three options, the first would be asking for a fetch_array() equlivant for prepared statements, which will provide full SQL injection prevention due to prepared statements sending data as raw.
The first question in this format follows:
I'm using a Query as:
$GetCompletedQuery = $STD->query("SELECT Status FROM UserCompletion WHERE `UserID`=' ". $STD->real_escape_string($_SESSION['UID']) ."'");
$GetCompletedArray = $GetCompletedQuery->fetch_array(MYSQLI_ASSOC);
Which returns:
Array ( [Status] => 1 )
But using prepared statements:
$GetCompletedQuery = $STD->prepare("SELECT Status FROM UserCompletion WHERE `UserID`=?");
$GetCompletedQuery->bind_param('i', $_SESSION['UID']);
$GetCompletedQuery->execute();
$GetCompletedArray = $GetCompletedQuery->fetch_row;
print_r($GetCompletedArray);
Which returns:
Fatal error: Call to a member function fetch_row() on a non-object in /var/www/New/API/Constants.php on line 17
The same appears when I try fetch_array() which I know cannot be used with prepared statements.
So what would be the option for using prepared statements?
Second Question
If I use My Usual Query as:
$GetCompletedQuery = $STD->query("SELECT Status FROM UserCompletion WHERE `UserID`=' ". $STD->real_escape_string($_SESSION['UID']) ."'");
which enabled me to use fetch_array(); is data properly secured from SQL injection?
Third Question:
Should I be escaping/protecting from SQL injection for a $_SESSION['UID']; as this is assigned in the following manor:
$InnerJoinQuery = $STD->query("
SELECT Users.ID, Users.Username, Users.Password, UserInformation.LastName, UserInformation.Firstname, UserInformation.DOB
FROM Users
INNER JOIN UserInformation
ON Users.ID = UserInformation.UserID WHERE Users.Username = '".$_SESSION['real_name']."'");
$InnerJoinArray = $InnerJoinQuery->fetch_array(MYSQLI_ASSOC);
$_SESSION['UID'] = $InnerJoinArray['ID'];
$_SESSION['Password'] = $InnerJoinArray['Password'];
$_SESSION['Firstname'] = $InnerJoinArray['Firstname'];
$_SESSION['LastName'] = $InnerJoinArray['LastName'];
$_SESSION['DOB'] = $InnerJoinArray['DOB'];
This snippet explained:
User Logs in with username & password, the file gets information from the database based on $_SESSION['real_name'];
and adds to the $_SESSION array with the results, adding each into a different key.
The question for this chunk is should I even be escaping/protecting from SQL injection when the $_SESSION['UID']; is assigned through the database based on $_SESSION['real_name'];
Thankyou for your time for reading over this massive chunk.
http://php.net/manual/en/mysqli-stmt.get-result.php
Yes, but it is very bad practice:
it will help you in this case but only in this case and deceive with anything else
manual escaping is just silly, better let driver to do it for you
YES, because there is no such thing like SQL injection but improper formatting ONLY
is that using $mysqli->real_escape_string($Var); does not provide protection against SQL Injection?
I didn't change my mind: sure, it doesn't.
It will do only if you enclose the resulting value in quotes (and set proper encoding using mysqli_set_charset() to be strict).
Look, SQL injection not something essential, existing on it's own, but it's rather mere a consequence. A consequence of improperly formatted query.
When creating a query, you have to properly format every part of it. Not because of whatever "injection" but for the sake of it. When you're going to insert a string into query, you HAVE to put it into quotes, or you will get a syntax error. When you're going to insert a string into query, you HAVE to escape these quotes were used to delimit this string, or you will get a syntax error. And so on. It is proper formatting that should be your concern, not scaring tales about injection. And as long as you have every dynamic query part properly formatted according to it's type - no injection ever could be possible
So, the source of variable or it's value should never be your concern. But only it's place in the query:
strings have to be enclosed in quotes and have these quotes escaped.
numbers have to be cast to it's type.
identifiers have to be enclosed in backticks and have these backticks doubled
When it's going for the static part of the query, hardcoded in the script, we don't use such strict standards - say, we're not enclosing every identifier in backticks.
But when it's going for the dynamical part of the query, applying formatting rules should be strict rule, as we cannot know variable content for sure.
By the way, there is another way to format your strings and numbers - prepared statements. It is not as convenient as it should be, but because it is using placeholders to represent your data in the query, it it recommended to use over silly manual formatting.
I've been coding my website in PHP lately and I was pretty proud of myself for my good practices of sanitizing my input before I used it in a query. It was all going great until my friend said I need to sanitize my input. When I tried to explain to him that it was sanitized, he showed me that he had found everything in 'users' table in my database. I didn't know how, so I thought I would post what I was doing wrong that made my sanitizing not work. Here is the PHP code he was exploiting:
start_mysql(); // Starts the databases stuff, etc.
$id = mysql_real_escape_string($_GET['id']);
$game = mysql_query("SELECT * FROM `games` WHERE `id` = $id LIMIT 0, 1");
All he was doing was changing the id parameter, making him able to use SQL injection on my database. I thought mysql_real_escape_string escaped all characters like that, but apparently I was wrong. I did some tests with a normal string to see what would happen, and this is what it said
URL: /game.php?id=' OR '' = '
echo($_GET['id']); // This echo'd: \' OR \'\' = \'
echo(mysql_real_escape_string($_GET['id'])); // This echo'd: \\\' OR \\\'\\\' = \\\'
So, my simple question is, what am I doing wrong?
You need to put the escaped string in single quotes:
WHERE `id` = '$id'
Since id was an integer parameter and you did not surround it in single-quotes in your SQL, the value of $id is sent directly into your query. If you were expecting an integer id, then you should verify that the value of $_GET['id'] is a valid integer.
$id = intval($_GET['id']);
Matt,
mysql_real_escape_string() will only filter for certain characters, if you truly want to prevent injection attacks check out this other Stack Overflow article that suggests you use Prepared statements:
Prepared Statements
PHP Manual entry on Prepared statements
Edit: Also check out Slaks and Michael's postings about wrapping your variable in single quotes.
Good luck!
H
Cast ID. If it is a string it will cast as 0.
$id = (int)$_GET['id'];
Also, MySQL support quotes around both string and numbers in the query.
$game = mysql_query("SELECT * FROM `games` WHERE `id` = '$id' LIMIT 0, 1");
You need to use the parameter binding api. The problem is in this piece of code:
WHERE `id` = $id
You are directly interpolating user input into your SQL statement. That's the open barn door for SQL injection attacks.
You're not using parameterized queries.
MDB2 allows this, though that library may be falling out of favor.
It's very likely that your configuration has magic_quote_gpc, an ancien attempt in PHP to make scripts secure magically. It proved to have multiple flaws and was since deprecated and was scheduled to be completely removed in 5.4 the last time I heard of it.
If you have access to your php.ini configuration, you should disable it. Otherwise, you can modify your script to take it into account and sanitize your input.
All of this is documented here: http://www.php.net/manual/en/security.magicquotes.disabling.php
Otherwise, there is nothing wrong with mysqli_real_escape_string().
You can't prevent SQL injections using mysql_real_escape_string(). It is used for escaping special characters like single quotes ('), double quotes ("), etc.
To prevent SQL injections you have to use PDO statements and filter functions in PHP for sanitizing the user data.
I'm still learning about SQL injection, but always the best way for me was using examples, so this is part of my code:
$sql = "INSERT INTO `comments` (`id`, `idpost`, `comment`, `datetime`, `author`, `active`)
VALUES (NULL, '" . addslashes($_POST['idcomment']) . "', '" .
addslashes($_POST['comment']) . "', NOW(), '" .
addslashes($_POST['name']) . "', '1');";
mysql_query($sql);
Knowing that all the POST vars are entered by the user, can you show me how can i make an injection to this script? so i can understand more about this vulnerability. Thanks!
my database server is MySQL.
Don't use addslashes(), always use mysql_real_escape_string(). There are known edge cases where addslashes() is not enough.
If starting something new from scratch, best use a database wrapper that supports prepared statements like PDO or mysqli.
Most of the other answers seem to have missed the point of this question entirely.
That said, based on your example above (and despite your code not following the best practice use of mysql_real_escape_string()) it is beyond my ability to inject anything truly detrimental when you make use of addslashes().
However, if you were to omit it, a user could enter a string into the name field that looks something like:
some name'; DROP TABLE comments; --
The goal is to end the current statement, and then execute your own. -- is a comment and is used to make sure nothing that would normally come after the injected string is processed.
However (again), it is my understanding that MySQL by default automatically closes the DB connection at the end of a single statement's execution. So even if I did get so far as to try and drop a table, MySQL would cause that second statement to fail.
But this isn't the only type of SQL injection, I would suggest reading up some more on the topic. My research turned up this document from dev.mysql.com which is pretty good: http://dev.mysql.com/tech-resources/articles/guide-to-php-security-ch3.pdf
Edit, another thought:
Depending on what happens to the data once it goes to the database, I may not want to inject any SQL at all. I may want to inject some HTML/JavaScript that gets run when you post the data back out to a webpage in a Cross-Site Scripting (XSS) attack. Which is also something to be aware of.
As said before, for strings, use mysql_real_escape_string() instead of addslashes() but for integers, use intval().
/* little code cleanup */
$idcomment = intval($_POST['idcomment']);
$comment = mysql_real_escape_string($_POST['comment']);
$name = mysql_real_escape_string($_POST['name']);
$sql = "INSERT INTO comments (idpost, comment, datetime, author, active)
VALUES ($idcomment, '$comment', NOW(), '$name', 1)";
mysql_query($sql);
Addslashes handles only quotes.
But there are some more important cases here:
Be careful on whether you use double or single quotes when creating the string to be escaped:
$test = 'This is one line\r\nand this is another\r\nand this line has\ta tab';
echo $test;
echo "\r\n\r\n";
echo addslashes($test);
$test = "This is one line\r\nand this is another\r\nand this line has\ta tab";
echo $test;
echo "\r\n\r\n";
echo addslashes($test);
Another one:
In particular, MySQL wants \n, \r and \x1a escaped which addslashes does NOT do. Therefore relying on addslashes is not a good idea at all and may make your code vulnerable to security risks.
And one more:
Be very careful when using addslashes and stripslashes in combination with regular expression that will be stored in a MySQL database. Especially when the regular expression contain escape characters!
To store a regular expression with escape characters in a MySQL database you use addslashes. For example:
$l_reg_exp = addslashes( �[\x00-\x1F]� );
After this the variable $l_reg_exp will contain: [\\x00-\\x1F].
When you store this regular expression in a MySQL database, the regular expression in the database becomes [\x00-\x1F].
When you retrieve the regular expression from the MySQL database and apply the PHP function stripslashes(), the single backslashes will be gone!
The regular expression will become [x00-x1F] and your regular expression might not work!
Remember, that the magic may happen in:
addslashes which may miss something
before adding to database
after retrieving from database
Your example is just an excerpt. The real problem might not be visible here yet.
(based on comments from php.net which are very often more valuable than the manual itself )
I have a textarea in a form, when I enter special characters in it, I get an error in mysql. (when submitting the form to a php-file which does the work of inserting into mysql)
I need to know exactly what characters that aren't allowed, or easier would be, exactly what characters thar ARE allowed, so that I could validate the textarea before submitting.
Does anybody know?
I have tried mysql_real_escape_string() but didn't help...
NOTE: In the textarea, users are supposed to enter some special chars like these:
+ , . ; : - _ space & % ! ? = # * ½ # / \ [ ] ' " < > £ $ €
Probably got them all...
how can I do this?
Thanks
UDPATE
My mysql_query :
mysql_query("INSERT INTO cars_db (description) VALUES ('$ad_text')");
UPDATE
Mysql error:
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 'a"a!a?aa+a-a_a
a/a\a[a]a}a{a&a%a#a#a¨a^a*a*aa,a.a:a;a|a½a
§a' at line 1
A database column can technically hold any of those characters. The problem is that you are not escaping them properly in your query.
One way way to do this using mysql_real_escape_string is as follows:
$sql=sprintf("insert into cars_db (description) values ('%s')",
mysql_real_escape_string($_POST['description']) );
//execute query and show errors that result...
$result = mysql_query($sql);
if (!$result) {
die("Oops:<br>$sql<br>".mysql_error());
}
Another way is to use a library like PDO or ADODb which makes it easier to use prepared statements with placeholders. Such libraries ensure that data injected into queries is properly escaped.
This is good practice not only because it solves your problem, but it also improves the security of your code, since it becomes harder to perform SQL injection attacks.
Another way would be to use prepared statements. This makes sure SQL injection isn't possible.
Instead of escaping characters so as not to trip up your query, why not create a stored procedure with an incoming String parameter. Just pass the form variable's value (or save it to a string) and pass that to the stored procedure.
Do this:
$ad_text = mysql_real_escape_string($ad_text);
mysql_query("INSERT INTO cars_db (description) VALUES ('$ad_text')");
Read up on mysql_real_escape_string and SQL injection. This is a massive security hole in your application.
http://us.php.net/mysql_real_escape_string