I have several post variables that I run through the following:
$input_name = mysqli_real_escape_string($dbc, trim($_POST['input_name']));
I have run several tests where I echo $input_name and other like variables before the insert query executes. The echo indicates that they are indeed getting escaped as they should.
However, when I login to phpmyadmin to look at my entries in the DB, I see that characters that should be escaped are not. Do I have a problem here? Is something happening between my variable declaration and the query that I am not aware of?
Are there php or server settings that could be influencing this?
note: I realize PDO is the way to go, I am just not there at this particular moment.
The echo indicates that they are indeed getting escaped as they should.
This indicates that your characters are escaped.
when I login to phpmyadmin to look at my entries in the DB, I see that characters that should be escaped are not
Now as you are escaping means that you want to those characters as it is rather than PHP or you database taking them internally as delimiters.
Like if you want ' in your input as it is, so your are escaping it.
So now when database(mysql) sees it that is is escaped so it won't considered it as a single quote that is used for string literals in MySQL.
If you don't escape it then MySQL will consider all the part between two ' as string literals.
So everything is fine, don't worry about it.
The *_real_escape_string functions in PHP are only there to prevent SQL injection therefor it will only change " to \" and ' to \' so that the following query:
SELECT * FROM users WHERE pass = '' OR '1'='1 --
Will become:
SELECT * FROM users WHERE pass = '\' OR \'1\'=\'1 --
So that the injected value won't work.
Related
I'm running this exact query from PHP:
UPDATE commentedText SET title='§2.', content='<div class=\"pageParagraph\"><p>Test</p>\n</div>', last_changed='1430422172', image_banner_url='', active='', comments='[{"from":"0","to":"0","id":"1","CommentedText":"","comment":"New test with \"test\" :d"}]' WHERE id='5541d52beb2ea' AND appId='MyAppID' LIMIT 1
However when I read the row that was updated (either via PHP or MySQL Workbench), the slashes are gone. See for example
<div class=\"pageParagraph\"[..]
which is saved to the table as
<div class="pageParagraph"[..]
How come the slashes disappear?
They are disappearing before they even get to MySQL -- PHP is seeing the backslash as an escape for the double quote.
"\""
creates a string "
To keep the backslash use
"\\\""
The first escapes the second, and the third escapes the quote.
Mysql also uses backslash escapes for strings. So to use it in a query, you need to have it escaped yet again.
"\\\\\""
PHP's string will be \\"
Which in MySQL will create a string \"
Use proper escaping when dealing with queries. Applying things like addslashes() are easily defeated.
Depending on your library, mysql_real_escape_string(), mysqli_real_escape_string(), or best yet, prepared statements.
These methods of escaping will not modify the original data, so you don't have to worry about removing the escaping characters on render.
We are developing a small website at school, so we were introduced to SQL injection in PHP and how to prevent it.
However I see most online examples and text books doing the following
$str = $_POST['user_input'];
$str = $mysqli->real_escape_string($str);
$str = htmlentities($str);
However I think the most logical way to validate input from users is:
$str = htmlentities($str);
$str = $mysqli->real_escape_string($str);
Does that make any difference for
Site accessibility (characters showed to end user, the string will just be "echoed" once retrieved from Database)
Preventing HTML and SQL injection (does wrong order allows injection?)
Performance of the server (for example one function is most expensive while the other increase string lenght, or just because the final string lenght is different and we want to save bytes on our Database)
?
Would be nice to cover also more escaping functions (maybe there is some dangerous combination/order that we should avoid).
I think that the right way is to search for escaping functions that outputs "dangerous characters" (dangerouse as HTML or as SQL, if any exist) and then just provide an input that generate those dangerous characters.
The order will result in different output.
The following code:
$string = 'Example " string';
echo htmlentities($mysqli->real_escape_string(($string))
. "\n"
. $mysqli->real_escape_string((htmlentities($string));
Results in:
Example \" string
Example " string
The output is different because if you escape the string before converting to HTML entities, it has a quote that needs escaping whereas if you do it in the reverse order the quote is replaced with the HTML entity and is a valid string value for MySQL.
That said, the two functions have entirely different purposes.
htmlentities is for converting strings to their HTML entities ready for output to a web browser.
real_escape_string is for converting a string for use between quotation marks in a MySQL query.
The two do not go together, you should store the text in the database (which will need escaping before being passed to) and convert to HTML entities when it comes to displaying it.
If you insist on storing the HTML entities version of the string in the database the correct way is to use htmlentities first, then escape it. Escaping of a string should be the last operation on it before passing to the database.
Doing it in the wrong way may result in stray backslashes as shown above, although when passed to MySQL these will actually be ignored as \& is not a valid escape sequence. You would only notice a difference if outputting the variable that was passed to the database (as opposed to later retrieving it from the database and then outputting it).
You may also want to look into prepared statements in mysqli:
http://www.php.net/manual/en/mysqli.prepare.php
When I post a variable to the database, of course, I use mysql_real_escape_string. This way special characters go in the database as it should.
When I read this variable out of the database, I use mysql_real_escape_string again together with stripslashes:
$var = stripslashes(mysql_real_escape_string($record['rowname']));
else it will give me slashes before quotes.
When I use this $var I mentioned above and want to echo it, I simple can echo "$var" because it has already been stripped and escaped, right?
And beside, if I use stripslashes + mysql_real_escape_string on a variable, then POST this same variable again in the database, is mysql_real_escape_string enough? Or do I need to stripslashes this variable again?
Summarized:
As I know how this works:
use mysql_real_escape EVERY time when using data with mysql: when reading query through variables just as posting variables to database.
Use stripslashes when echoing out escaped variables.
If you want to post stripslashes and escaped variables again to the database, you dont need to stripslash it again.
Do I miss htmlspecialchars?
EDIT
So this is all wrong?
while( $record=mysql_fetch_array($result) )
{
$custid=mysql_real_escape_string($record['custid']);
$custsurname=mysql_real_escape_string($record['custsurname']);
$custmidname=mysql_real_escape_string($record['custmidname']);
$custforename=mysql_real_escape_string($record['custforename']);
$custcountry=stripslashes(mysql_real_escape_string($record['custcountry'])); }
I'm afraid you're doing it wrong. The key point is that escaping is context sensitive and you completely disregard that fact.
On every data format, there're words or characters that are assigned special meanings in the format spec. For instance, a ' symbol in SQL means "string delimiter", a ? symbol in a URL means "start query string" and a < symbol in HTML means "start tag". You need escaping when you want to insert a literal word or character, i.e., you want to insert it as-is and remove its special meaning.
Once aware of that, it's clear that the syntax varies depending on the format and context. < means "start tag" in HTML but not in SQL or URLs. Thus you need to use a escaping method that's built for the target format and follows the format rules.
If you do mysql_real_escape_string() on data read from a database you're saying "escape my data so it can be injected as inside a SQL string". Your data gets ready to be used inside as a SQL string but get's corrupted for any other usage.
In this example, it happens that stripslashes() undoes most of what mysql_real_escape_string() did so you end up with an output that's basically unchanged. But that's pure chance.
Last but not least, having to escape database input parameters one by one is very annoying. All other DB extensions but the one you are using1 offer prepared statements. Don't get stuck with a deprecated extension that doesn't offer modern stuff.
1 Note: the legacy mysql extension has been deprecated for several years, when better alternatives became available, and it's no longer part of the language.
Update: a little clarification—escaping is just a syntax trick. You don't alter the input to the eyes of the target engine, which just sees the original data as-is. So there's no need to unescape the input when you retrieve it.
You don't need to stripslashes or mysql_real_escape_string the data coming from database, you just need to escape it before you query so the query parser knows what are special characters and what are literal characters.
stripslashes should be never used (as a hack to fix some symptoms), if you are going to need a variable after escaping it, use the original one:
$data_safe = mysql_real_escape_string( $data );
//$data can still be used normally
Escaping is only for a certain context, if the context is a mysql query then you will mysql real escape just for the query and nothing else. If the context is html output, then you will htmlescape just before outputting a string as html. At no point you want to actually modify the data itself. If you misunderstand this, you will see O\'Brian and O'Brian etc.
I was reading Does $_SESSION['username'] need to be escaped before getting into an SQL query? and it said "You need to escape every string you pass to the sql query, regardless of its origin". Now I know something like this is really basic. A Google search turned up over 20, 000 results. Stackoverflow alone had 20 pages of results but no one actually explains what escaping a string is or how to do it. It is just assumed. Can you help me? I want to learn because as always I am making a web app in PHP.
I have looked at:
Inserting Escape Characters, What are all the escape characters in Java?,
Cant escape a string with addcslashes(),
Escape character,
what does mysql_real_escape_string() really do?,
How can i escape double quotes from a string in php?,
MySQL_real_escape_string not adding slashes?,
remove escape sequences from string in php I could go on but I am sure you get the point. This is not laziness.
Escaping a string means to reduce ambiguity in quotes (and other characters) used in that string. For instance, when you're defining a string, you typically surround it in either double quotes or single quotes:
"Hello World."
But what if my string had double quotes within it?
"Hello "World.""
Now I have ambiguity - the interpreter doesn't know where my string ends. If I want to keep my double quotes, I have a couple options. I could use single quotes around my string:
'Hello "World."'
Or I can escape my quotes:
"Hello \"World.\""
Any quote that is preceded by a slash is escaped, and understood to be part of the value of the string.
When it comes to queries, MySQL has certain keywords it watches for that we cannot use in our queries without causing some confusion. Suppose we had a table of values where a column was named "Select", and we wanted to select that:
SELECT select FROM myTable
We've now introduced some ambiguity into our query. Within our query, we can reduce that ambiguity by using back-ticks:
SELECT `select` FROM myTable
This removes the confusion we've introduced by using poor judgment in selecting field names.
A lot of this can be handled for you by simply passing your values through mysql_real_escape_string(). In the example below you can see that we're passing user-submitted data through this function to ensure it won't cause any problems for our query:
// Query
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
Other methods exist for escaping strings, such as add_slashes, addcslashes, quotemeta, and more, though you'll find that when the goal is to run a safe query, by and large developers prefer mysql_real_escape_string or pg_escape_string (in the context of PostgreSQL.
Some characters have special meaning to the SQL database you are using. When these characters are being used in a query they can cause unexpected and/or unintended behavior including allowing an attacker to compromise your database. To prevent these characters from affecting a query in this way they need to be escaped, or to say it a different way, the database needs to be told to not treat them as special characters in this query.
In the case of mysql_real_escape_string() it escapes \x00, \n, \r,\, ', " and \x1a as these, when not escaped, can cause the previously mentioned problems which includes SQL injections with a MySQL database.
For simplicity, you could basically imagine the backslash "\" to be a command to the interpreter during runtime.
For e.g. while interpreting this statement:
$txt = "Hello world!";
during the lexical analysis phase ( or when splitting up the statement into individual tokens) these would be the tokens identified
$, txt, =, ", Hello world!, ", and ;
However the backslash within the string will cause an extra set of tokens and is interpreted as a command to do something with the character that immediately follows it :
for e.g.
$txt = "this \" is escaped";
results in the following tokens:
$, txt, =, ", this, \, ", is escaped, ", and ;
the interpreter already knows (or has preset routes it can take) what to do based on the character that succeeds the \ token. So in the case of " it proceeds to treat it as a character and not as the end-of-string command.
I got this from for a login form tutorial:
function sanitize($securitystring) {
$securitystring = #trim($str);
if(get_magic_quotes_gpc()) {
$securitystring = stripslashes($str);
}
return mysql_real_escape_string($securitystring);
}
Could some one explain exactly what this does? I know that the 'clean' var is called up afterwards to sanitize the fields; I.e. $email = sanitize($_POST['email']);
Basically, if you have magic quotes switched on, special characters in POST/SESSION data will automatically be escaped (same as applying addslashes() to the string). The MySQL escape functions are better than PHP's addslashes() (although I can't remember the exact reasons why).
What your code does is check if the php.ini file has magic quotes turned on, if so the slashes are stripped from the data and then it is re-sanitised using the MySQL function. If magic quotes is not on, there is no need to strip slashes so the data is just sanitised with the MySQL function and returned.
First of all, this code is wrong.
It has wrong meaning and wrong name.
No SQL data preparation code does any cleaning or sanitization.
It does merely escaping. And this escaping must be unconditional.
and escaping shouldn't be mixed with anything else.
So, it must be three separated functions, not one.
Getting rid of magic quotes. Must be done separately at the data input.
trim if you wish. It's just text beautifier, no critical function it does.
mysql_real_escape_string() to prepare data for the SQL query.
So, the only mysql related function here is mysql_real_escape_string(). Though it makes no data "clean", but merely escape delimiters. Therefore, this function must be used only with data what considered as a string and enclosed in quotes. So, this is a good example:
$num=6;
$string='name';
$num=mysql_real_escape_string($num);
$string=mysql_real_escape_string($string);
$query="SELECT * FROM table WHERE name='$name' AND num='$num'";
while this example is wrong:
$num=6;
$string='name';
$num=mysql_real_escape_string($num);
$string=mysql_real_escape_string($string);
$query2="SELECT * FROM table WHERE name='$name' AND num=$num";
Even though $query2 would not throw a syntax error, this is wrong data preparation and mysql_real_escape_string would help nothing here. So, this function can be used only to escape data that treated as a string. though it can be done to any data type, there is some exceptions, such as LIMIT parameters, which cannot be treat as a strings.
trim() gets rid of all whitespace, and if magic quotes is on, the backslash is removed from any escaped quotes with stripslashes(). mysql_real_escape_string() readies a string to be used in a mysql query safely.
here are the docs for the functions used: http://php.net/manual/en/function.trim.php, http://php.net/manual/en/function.get-magic-quotes-gpc.php, http://php.net/manual/en/function.stripslashes.php, http://php.net/manual/en/function.mysql-real-escape-string.php
mysql_real_escape_string is used to escape characters in the string to add backslashes to characters such as ', which prevents an attacker from embedding additional SQL statements into the string. If the string is not escaped, additional SQL can be appended. For example, something along the lines of this might be executed:
SELECT * FROM tbl WHERE col = 'test' ; DELETE * FROM tbl ; SELECT 'owned'
magic_quotes does escaping of its own, although if I remember correctly its use is now discouraged. Besides, the MySQL function will do all the escaping you need to prevent SQL injection attacks.
Some (old) servers have magic_quotes enabled. That means that all external input is altered to (supposedly) escape it in order to be injected in a MySQL query. So O'Brian becomes O\'Brian. This was an early design decision by the PHP team that proved wrong:
You don't always need to inject input into database queries
Not all DB engines use back slashes as escape char
Escaping single quotes with backs slashes is not enough, even for MySQL
Your server security relies on a PHP setting that can be disabled
So it's way better to code without magic_quotes. The problem comes with redistributable code: you cannot know if the server will have magic_quotes enabled or disabled. So you can use get_magic_quotes_gpc() to detect it they're on and, if so, use stripslashes() to (try to) recover the original input.