I'm using PHP and Postgresql 9.0. I wish to insert a string eg.
"TiMxji+bhCJlk9OGcYosmBpEK8K+Li1Ygut9MJWFtpT8t0MlbGgMWJ7\/SHj8PjSWXoeGRmjjAqBTPQMe"
into a column using a prepared statement. The string generated is part of an authentication system and therefore must be entered exactly. My problem is that the backslashes are interpreted as escape characters rather than literal characters. Normally I believe I would just use the E operator to denote a string literal but this just throws up errors. Is there a way I can tell Postgres that this is a string literal while using a prepared statement?
Below is a simple example statement, where $1 is the string I wish to denote as a string literal.
pg_prepare($p->db,'setToken','UPDATE users SET token=$1 WHERE email=$2');
Thanks for your help,
Mark
$1 is the string I wish to denote as a string literal.
There's a contradiction in terms here, because writing a string as a literal is the opposite of feeding it via a parameter through the $1 placeholder.
If using a parameter, the code would be:
$result=pg_prepare($p->db, 'setToken','UPDATE users SET token=$1 WHERE email=$2');
// error checking on $result skipped
$result=pg_execute($p->db, 'setToken', array($token, $email));
If using $token and $email as string literals instead, the code could look like this:
$query = sprintf("UPDATE users SET token='%s' WHERE email='%s'",
pg_escape_string($p->db, $token),
pg_escape_string($p->db, $email));
$result=pg_prepare($p->db, 'setToken', $query);
// error checking on $result skipped
$result=pg_execute($p->db, 'setToken', array());
Both methods work, but method #1 is generally considered more foolproof and efficient.
Note about the backslash character: it is not true in general that \ must be escaped. In standard SQL, backslash is a normal character that must not be escaped. For compatibility reasons, PostgreSQL has a parameter standard_conforming_strings that when ON, tells that \ is normal, and when OFF tells it's an escape character.
The default value of this parameter is OFF up to 9.0 and ON starting with 9.1.
pg_escape_string knows about this setting and will take it into account automatically (unless you use an antiquated version of the postgresql client library).
And since you mentioned the E'...' prefix notation, when using it the \ is always an escape character in the string that follows, regardless of the standard_conforming_strings setting. General you don't want to stuff literals from php variables into E'...' postgresql constructs, it's unnecessarily hard because of the multiple levels of quoting involved.
Related
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Correct way to escape input data before passing to ODBC
the error I am getting from querying a ODBC query is this:
(pos: 72 '...M = 'Owen O'^Donavon' AND...') - syntax error
and when I try to escape it:
(pos: 73 '... = 'Owen O\'^Donavon' AND...') - syntax error
the ^ means that is where it is breaking
I have tried the following:
NAM = '".$var."'
And also this:
NAM = '".mysql_escape_string($var)."'
then I got desperate
NAM = \"".$var."\"
Where $var is any name that contains a ' in it.
if you need the whole query:
UPDATE TABLE SET COLUMN1 = 'ERR' WHERE COLUMN_NAM = '".mysql_escape_string($var)."' AND COLUMN7 = 0");
does anybody know how I can get the quote properly escaped?
To include a single quote within a MySQL string literal (which is delimited by single quotes), use two single quote characters. e.g.
'I don''t like it'
Effectively, When MySQL parses that, it will see the two single quote characters, and will interpret that as one single quote within a literal, rather than seeing the "end" of the string literal.
But (as you are finding out) when you have only one single quote in there, the MySQL parser has a hissy fit over it. Consider this example:
'I don't like it'
What the MySQL parser sees there is a string literal, five characters in length, containing 'I don'. Then MySQL sees that literal as being followed by some more tokens that need to be parsed: t like it. The parser does NOT see that as part of a string literal. That previous single quote marked the end of the string literal.
So now, the MySQL parser can't make heads or tails of what t like it is supposed to be. It sees the single quote following these tokens as the beginning of another string literal. (So, you could be very clever about what appears there, and manage to get something that MySQL does understand... and that would probably be even worse.)
(NOTE: this issue isn't specific to ODBC; this affects clients that make use of string literals in MySQL query text.)
One way to avoid this type of problem is to use bind variables in your query text, vs. string literals. (But with MySQL, what's happening anyway, is that escaping, what gets sent to the MySQL server (behind the scenes, so to speak) is a string literal.
Sometimes we DO need to include string literals in our query text, and we shouldn't be required to use bind variables as a workaround. So it's good to know how to "escape" a single quote within a string literal which is enclosed in single quotes.
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.
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'm using mysqli.
When I echo mysqli_real_escape_string($db,mysqli_real_escape_string($db,'"'));
which one of those will be the output:
1. \"
2. \\\"
?
Is there a safe way to check whether a string has been already escaped?
Unfortunately, I cannot test at present as I cannot access MySQL for 24 hours.
The output is \\\" (your second example).
I don't think you can reliably say whether a string has already been escaped or not, you should organize your code in a way that you only can call mysqli_real_escape_string() once.
You can't tell if a string has already been escaped, because a string that has been escaped could also have been entered a user (and therefore be unescaped).
The resulting string will be \\\" (escaping each of the two characters).
If by "safe" you mean "foolproof", then no. Even if you check that the relevant characters are escaped, you can't know if it was supposed to be \", and strings don't provide any hidden flags that could be set to mark it as having been escaped.
However, you shouldn't manually be calling mysqli_real_escape_string twice. Only do it at the moment you need it.
The main source of "double escaping" is when you're doing the right* thing by escaping, but neither turn off magic quotes or remove them if they're on.
*Well, as close as you can get without using parameterized queries.
The second one will be returned. " will first be converted to \" (escaping ") and that will then be converted to \\\" (escaping \ and ").
In general you do have to do it on your own. Although there is the “feature” Magic Quotes that does add backslashes to the character ', ", \ and the NULL character in your incoming data, Magic Quotes are a horrible invention and will be removed in PHP 6. Futhermore they can be enabled on one server and disable on another. So it’s not even reliable.
But more important is that they are not suitable for MySQL as in MySQL you not just have to take care of these meta characters only but of other character too (see string syntax in MySQL for more information).
Calling mysqli_real_escape_string() multiple times does not make the query less safe. It does however corrupt your data. A good example is Conan O'Brien.
If you do the following:
$name=mysqli_real_escape_string($db,mysqli_real_escape_string($db,"Conan O'Brien"));
//At this point $name is Conan O\\\'Brien
mysql_query("insert into table (name)values('$name')")
//In the database the name will be stored as: Conan O\'Brien Which is corrupt.
To deal with this corruption you can do the following:
funciton strip_all($var){
$len=strlen($var);
$ret=stripslashes($var);
while($len!=strlen($ret)){
$len=strlen($ret);
$ret=stripslashes($ret);
}
return ret;
}
//$name is unkown somthing like: Conan O\\\\\\\'Brien
$name=strip_all($name);
//$name is: Conan O'Brien
$name=mysqli_real_escape_string($db,$name);
//$name is: Conan O\'Brien, which is properly escaped.
mysql_query("insert into table (name)values('$name')")
//In the database the value is Conan O'Brien, mysql will eat the back slash.
The best approach is to keep track where your escaping is coming from. In this case we account if magic_quotes is disabled or enabled, and then we use mysqli_real_escape_string() which provides better security because it escapes more characters.
if(get_magic_quotes_gpc())
{
$name=stripslashes($_GET[name]);
}
$name=mysqli_real_escape_string($db,$_GET[name]);
//At this point $name is Conan O\'Brien
mysql_query("insert into table (name)values('$name')")
To add some extra information.
Escaping is a way to add extra information to a sequence of symbols without introducing extra symbols. In order to do this, at least one symbol gets to function as the 'escape' symbol. This means the original role is lost and needs to be added using an escape sequence.
Example:
We have a language with 3 symbols: a, b and c. In which the symbols have the following functions:
Language 1
a has the function A
b has the function B
c has the function C
We now need to introduce the functions D and E, but we are not able to add extra symbols.
So we can do this using an escape symbol:
Language 2
a, is now the escape symbol.
aa has the function A
ab had the function D
ac has the function E
b has the function B
c has the function C
The sequence aabcabac, if interpreted using language 1 reads AABCABAC. But interpreted using language 2 reads ABCDE.
The problem with this is that, most of the time, you are not able to determine the language used from the symbols. This meta information needs to be provided before the data is processed.
The botom line is that you have no safe way to determine if a string is escaped enough.