正如你所看到的,人们建议你最多使用准备好的陈述。这并没有错,但如果每个进程只执行一次查询,则会有轻微的性能损失。
我正面临这个问题,但我认为我以非常复杂的方式解决了它——黑客避免使用引号的方式。我将其与模拟的准备语句结合使用。我使用它来防止各种可能的SQL注入攻击。
我的方法:
如果您希望输入是整数,请确保它真的是整数。在像PHP这样的变量类型语言中,这一点非常重要。例如,您可以使用这个非常简单但功能强大的解决方案:sprintf(“SELECT 1,2,3 FROM table WHERE 4=%u”,$input);如果你对整数十六进制有任何期望,如果你对它十六进制,你将完全逃避所有输入。在C/C++中有一个名为mysql_hex_string()的函数,在PHP中可以使用bin2hex()。不用担心转义字符串的大小是其原始长度的2倍,因为即使使用mysql_real_ascape_string,PHP也必须分配相同的容量((2*input_length)+1),这是相同的。这种十六进制方法通常在传输二进制数据时使用,但我认为没有理由不对所有数据使用它来防止SQL注入攻击。请注意,您必须在数据前面加上0x,或者改用MySQL函数UNHEX。
例如,查询:
SELECT password FROM users WHERE name = 'root';
将变成:
SELECT password FROM users WHERE name = 0x726f6f74;
or
SELECT password FROM users WHERE name = UNHEX('726f6f74');
Hex是完美的逃脱。无法注射。
UNHEX函数与0x前缀之间的差异
评论中有一些讨论,所以我最后想说清楚。这两种方法非常相似,但在某些方面略有不同:
0x前缀只能用于char、varchar、text、block、binary等数据列。此外,如果要插入空字符串,则其使用有点复杂。您必须将其完全替换为“”,否则会出现错误。
UNHEX()适用于任何列;你不必担心空字符串。
十六进制方法通常用作攻击
注意,这种十六进制方法通常被用作SQL注入攻击,其中整数就像字符串一样,并且只使用mysql_real_aescape_string进行转义。然后可以避免使用引号。
例如,如果你只是这样做:
"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
攻击很容易给你注射。考虑从脚本返回的以下注入代码:
SELECT ... WHERE id = -1 UNION ALL SELECT table_name FROM information_schema.tables;
现在只提取表结构:
SELECT ... WHERE id = -1 UNION ALL SELECT column_name FROM information_schema.column WHERE table_name = __0x61727469636c65__;
然后只需选择所需的数据。是不是很酷?
但如果可注入站点的编码器将其十六进制,则不可能进行注入,因为查询将如下所示:
SELECT ... WHERE id = UNHEX('2d312075...3635');