38
votes

On http://www.justinshattuck.com/2007/01/18/mysql-injection-cheat-sheet/?akst_action=share-this , there is a section that claims you can bypass mysql_real_escape_string with certain Asian character encodings

Bypassing mysql_real_escape_string() with BIG5 or GBK

"injection string"
に関する追加情報:

the above chars are Chinese Big5

Is this really true? And if so, how would you protect your website against this, if you had no access to prepared statements?

4
justinshattuck.com gives me a malware warning on Chrome, maybe his site got hacked too.user967451
The characters in your injection string are not really BIG5. Some vendors extended BIG5 to include Japanese kana, but the standard does not include kana.Windows programmer

4 Answers

25
votes

According to Stefan Esser, "mysql_real_escape_string() [is] not safe when SET NAMES is used."

His explanation, from his blog:

SET NAMES is usually used to switch the encoding from what is default to what the application needs. This is done in a way that mysql_real_escape_string doesn’t know about this. This means if you switch to some multi byte encoding that allows backslash as 2nd 3rd 4th… byte you run into trouble, because mysql_real_escape_string doesn’t escape correctly. UTF-8 is safe…

Safe way to change encoding is mysql_set_charset, but that is only available in new PHP versions

He does mention that UTF-8 is safe, though.

19
votes

This is a MySQL server bug that was reportedly fixed way back in May 2006.

See:

  • MySQL bug #8303: String literals with multi-byte characters containing \ are lexed incorrectly
  • MySQL Bug #8317: Character set introducer in query fails to override connection character set
  • MySQL Bug #8378: String escaped incorrectly with client character set 'gbk'
  • MySQL 5.1.11 changelog.

The bug was reported fixed in MySQL 4.1.20, 5.0.22, 5.1.11.

If you use 4.1.x, 5.0.x, or 5.1.x, make sure you have upgraded at least to the minor revision numbers.

As a workaround, you can also enable the SQL mode NO_BACKSLASH_ESCAPES which disables backslash as a quote-escape character.

3
votes

I'm pretty sure it only doesn't work if you use SQL to change the char encoding.

1
votes

As others have demonstrated, mysql_real_escape_string() can be bypassed in obscure edge cases. That's one known strategy for bypassing the escaping logic, but there could be other unknown vulnerabilities that have not been discovered yet.

The simple and effective way to prevent SQL injection in PHP is to use prepared statements where you can, and a very strict whitelist where you can't.

Prepared statements, when actually used and not emulated by the PDO driver, are provably secure (at least with regards to SQL injection), as they solve a fundamental problem with application security: they separate the data from the instructions that operate on the data. They're sent in separate packets; the parameterized values never have a chance to taint the query string.

It's 2015. Don't escape and concatenate anymore. You should still validate your inputs according to application (and business) logic, but just use prepared statements.