"Help! My mysql_real_escape_string() isn't working!"
If you've ever Googled "SQL injection that gets around mysql_real_escape_string()", you're not alone. This question on Stack Overflow has gathered tens of thousands of views and become a classic in web security. It would seem you just use mysql_real_escape_string() and you're protected. But no. Hackers find loopholes, and developers find gray hairs.
In this article, we'll break down exactly how SQL injections can bypass mysql_real_escape_string() escaping in PHP. You'll see real code examples, understand why the "good old" approach no longer works, and learn how to truly protect yourself. Let's go!
Why mysql_real_escape_string() is not a panacea?
First, a bit of history. The mysql_real_escape_string() function appeared in the era of PHP 4 and 5, when everyone was using the mysql_* extension. It escapes special characters like quotes, backslashes, and control characters. But the problem is that it only works within the context of a single encoding.
If the client and server encodings don't match, chaos ensues. And if you're using multi-byte encodings (e.g., GBK or SJIS), the function can become your worst enemy.
Classic example: multi-byte attack
Imagine your site uses the GBK encoding (Chinese), and you pass the string:
$_POST['name'] = "0xbf27"; // Escaped ' or just '?In GBK, the character 0xbf27 is a valid Chinese character. But if mysql_real_escape_string() "sees" 0x27 (apostrophe), it escapes it with a backslash: 0xbf5c27. The problem is that 0xbf5c is also a valid character in GBK! As a result, the apostrophe 0x27 remains unescaped, and the hacker can inject their SQL code.
// Vulnerable code$name = mysql_real_escape_string($_POST['name']);$query = "SELECT * FROM users WHERE name = '$name'";
// If you input: 0xbf27// The function returns: 0xbf5c27// In GBK this is: Chinese character + apostrophe// The query becomes: SELECT * FROM users WHERE name = 'chinese_char' OR 1=1 -- 'Voila! Injection successful. And this isn't just theory — such vulnerabilities have been found in real projects.
Typical vulnerabilities when using mysql_real_escape_string()
Let's list the most common mistakes that allow bypassing escaping:
- Incorrect encoding — as in the example above. If the server thinks the data is in UTF-8, but the client sends GBK, the escaping breaks.
- Using numeric fields without quotes — if you insert a number directly, escaping won't work. For example:
SELECT * FROM users WHERE id = $id— and the hacker writes1 OR 1=1. - LIKE queries — escaping does not handle
%and_characters. Blind SQL injection can be performed through patterns. - Double escaping — if you call the function twice, the backslash is doubled, and protection is lost.
Example: attack on a numeric field
// Vulnerable code$id = mysql_real_escape_string($_GET['id']);$query = "SELECT * FROM products WHERE id = $id"; // Quotes are not needed!
// Hacker inputs: 1 UNION SELECT username, password FROM users// The query becomes: SELECT * FROM products WHERE id = 1 UNION SELECT username, password FROM usersEscaping is useless here — there are no quotes to escape. The hacker simply inserts their SQL directly.
Modern protection methods (that work)
Enough horror stories — let's get to solutions. If you're writing PHP and want to forget about SQL injections, here's your checklist:
1. Use PDO or MySQLi with prepared statements
This is