使用十六进制编码来防止SQL注入有任何缺点吗?

mes*_*ssy 7 php mysql sql-injection

在SO上阅读一些SQL注入问题和答案,我看到这个答案表明你可以将不受信任的用户输入转换为十六进制,这本质上不需要任何类型的转义,因此完全和完全避免了SQL的可能性注射.

您使用的数据库抽象层(PDO,mysqli,mysql,Pear DB等)无关紧要.

正常工作查询的示例:

$DBH = new PDO('mysql:host=127.0.0.1;dbname=test', 'test', 'testpassword');

// could have been:
//$bookTitle = bin2hex($_GET['title']);
$bookTitle = bin2hex('Catch-22');

$query = "SELECT * from `books` WHERE `title` = UNHEX('$bookTitle')";

foreach ($DBH->query($query) as $row) {
    echo "\n<br />\n";
    print_r($row);
    echo "\n<br />\n";
}
Run Code Online (Sandbox Code Playgroud)

我已经在这里提供了足够的代码供您快速运行测试,如果您有一个包含表的数据库,例如:

CREATE TABLE `books` (`id` INT, `title` VARCHAR(100), `author` VARCHAR(100)) ENGINE=InnoDB CHARACTER SET='utf8';
INSERT INTO `books` VALUES(1, 'Catch-22', 'Joseph Heller');
Run Code Online (Sandbox Code Playgroud)

当然这是过于简单的 - 你通常有输入验证,输出消毒和许多其他抽象,但我们想要专注于这个问题 - 没有必要提供足够的松散来帮助提供易于执行的例子.

我想知道的是这项技术是否存在任何技术缺陷.我特别问这种技术是否存在人为弱点(作为一个草率的程序员更容易做到,因为它显然不如使用参数化查询那么干净).

是的,我们都同意参数化查询不易受到糟糕的编程或不幸的疏忽的影响.所以请坚持这个问题 - 这项技术是否有助于无条件地避免各种SQL注入?

有人可以展示一个破坏这种技术的用户输入的例子吗?即使是一个极端情况,一些特定的MySQL服务器设置或破坏它的旧PHP版本?

它适用于整数替换:

// could have been:
//$bookID = bin2hex($_GET['id']);
$bookID = bin2hex(1);

$query = "SELECT * from `books` WHERE `id` = UNHEX('$bookID')";
Run Code Online (Sandbox Code Playgroud)

其他想法:

  • 使用这种技术,如果使用(非仿真的)预处理语句(尽管是预处理语句!=参数化查询),您可以避免两次往返数据库.

  • 对其他一些建议技术的警告开始让人们用角落案例例如这个这个对象进行交叉.十六进制编码技术是否避免了攻击者使用字符集编码技巧和其他任何东西造成破坏的可能性?

  • 似乎数据库端的解码可能仅限于MySQL/MariaDB,尽管可能有第三方解决方案将UNHEX()添加到PostgreSQL(或者 - 不确定 - 在某些数据库中,您可能可以使用其他方法在不使用任何UNHEX函数的情况下将十六进制文字放在查询中

小智 -3

看起来合乎逻辑,因为所有数据,甚至可能导致注入的用户输入,都会被转换。我一直在尝试寻找绕过它的方法,但我做不到。到目前为止,我看到的最大缺点是: 1)从数据库视图来看,您将无法理解用户的输入。您将从数据库中提取所有内容并进行转换,以便查看或操作它。2)无论您提供什么输入,转换后字符串长度都会加倍。

  • 你真的测试过吗?- 因为您的评论表明您没有注意到表中的数据不是十六进制的。十六进制只是该方案中的传输编码。 (2认同)