Reputation:
I was explaining parametrization and its advantages to my friend recently, and he asked how it was any better than mysqli_escape_string
in terms of security. Specifically, can you think of any examples of SQL injection that would succeed despite the input strings being escaped (using mysqli_escape_string)?
UPDATE:
I apologise for not being clear enough in my original question. The general question being asked here is, is SQL injection possible despite escaping input strings?
Upvotes: 3
Views: 4552
Reputation: 57388
Specifically, can you think of any examples of SQL injection that would succeed despite the input strings being escaped (using mysql_escape_string)?
Not reliably. You are referring to mysql_escape_string()
, which does not take into account the connection encoding (while mysql_real_escape_string()
does).
So maybe a carefully crafted string, with a carefully crafted incomplete UTF8 codepoint in front, might result in, say, a quote sign being escaped by mysql_escape_string()
but the escape itself being ignored by MySQL since it will "see" it as an UTF8 character.
E.g.:
0xC2' OR 1=1 ;--
would be escaped by mysql_escape_string()
as
0xC2\' OR 1=1 ;--
which would be assembled to
WHERE password='0xC2\' OR 1=1 ;--';
and seen by MySQL (if the proper connection encoding was in effect) as, say,
WHERE password='€' OR 1=1 ;[--';] <-- the bracketed part is considered a comment and ignored
which would be a classic SQL injection.
But this plays on the fact that you specified, maybe through distraction, a doubly deprecated function. If you really were referring to mysql_real_escape_string()
, then it would not work.
Also, this assumes that neither the server, nor the application layer (e.g. PHP) employs any kind of charset validation when populating the input. If they did, the invalid UTF8 would be deleted on arrival, and never even be seen by mysql_escape_string
, which would then of course be enough.
Do not use mysql_escape_string
(or mysql_whatever
) at all. They've been deprecated and your code might stop working. Use PDO functions instead.
Upvotes: 4
Reputation: 437356
The question was edited (after my answer was posted) to specifically target mysqli_escape_string
, which is an alias of mysql_real_escape_string
and therefore takes the connection encoding into account. This makes the original answer non-applicable anymore, but I 've left it for completeness.
The new answer, in short: mysqli_escape_string
is as good security-wise as parameterized queries, provided you don't shoot yourself in the foot.
Specifically, what you must not do is highlighted in the giant warning on the PHP doc page:
The character set must be set either at the server level, or with the API function
mysqli_set_charset()
for it to affectmysqli_real_escape_string()
.
If you don't heed this warning (i.e. if you change the character set with a direct SET NAMES
query) and you change the character set from a single-byte encoding to a "convenient" (from the attacker's perspective) multibyte encoding, you will have in effect emulated what the dumb mysql_escape_string
does: attempt to escape characters without knowing which encoding the input is in.
This situation leaves you potentially vulnerable to SQL injection as described by the original answer below.
Important note: I remember reading somewhere that recent MySql versions have plugged this hole on their end (in the client libraries?), which means that you might be perfectly safe even if using SET NAMES
to switch to a vulnerable multibyte encoding. But please don't take my word for it.
In contrast to mysql_real_escape_string
, the bare mysql_escape_string
does not take into account the connection encoding. This means that it assumes the input is in a single-byte encoding, when in fact it can legitimately be in a multibyte encoding.
Some multibyte encodings have byte sequences that correspond to a single character where one of the bytes is the ASCII value of the single quote (0x27
); if fed such a string, mysql_escape_string
will happily "escape the quote", which means substituting 0x27
with 0x5c
0x27
. Depending on the encoding rules, this could result in mutating the multibyte character into another that includes the 0x5c
and leaving the "remaining" 0x27
as a stand-alone single quote in the input. Voilà, you have injected an unescaped quote into the SQL.
For more details see this blog post.
Upvotes: 4