但为什么你不翻译完?或者我们通过同一个链接看到的版本不是一个? LOL
>翻译完你给钱? 还有一种可能,要么是我的语文水平太差,要么是你英语太差
要点是这样的,这是那个 PO 主的 Demo:
$pdo->query('SET NAMES gbk');
$var = "\xbf\x27 OR 1=1 /*";
$query = 'SELECT * FROM test WHERE name = ? LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute(array($var));
注意,他没有用 $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
> 根据
https://secure.php.net/manual/zh/pdo.setattribute.php> PDO::ATTR_EMULATE_PREPARES 启用或禁用预处理语句的模拟。 有些驱动不支持或有限度地支持本地预处理。使用此设置强制 PDO 总是模拟预处理语句(如果为 TRUE ),或试着使用本地预处理语句(如果为 FALSE )。如果驱动不能成功预处理当前查询,它将总是回到模拟预处理语句上。 需要 bool 类型。
> 默认情况为 true,存在我翻译的问题
其实到这就不用看了,因为后面肯定会有问题:服务器所认为的链接字符集被设置成了 gbk,本地的未改变,而且 prepare 是在本地。
> 所以你想表达生命,再复述我的内容一遍?
然后那个 PO 主就挑了个 Easy Target,0xbf27 => addslashes() => 0xbf5c27 ( 0x5c == '\') => 字符串:縗'。
所以自然注入了。
这就是问题。所以这是一种 Charset Attack,利用字符串变形进行攻击。防御的方式也说了:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
> However, be aware that PDO will silently fallback to emulating statements that MySQL can't prepare natively
> This will usually result in a true prepared statement (i.e. the data being sent over in a separate packet from the query). However, be aware that PDO will silently fallback to emulating statements that MySQL can't prepare natively: those that it can are listed in the manual, but beware to select the appropriate server version).
下面是废话, 对 beware to select the appropriate server version 理解有问题,这不是解决方案,是让你注意看文档的时候选择正确的文档去看,因为不同版本的 MySQL fallback 的条件不同。
我们再看回答主的第一句话
>> I'm adapting this answer to talk about PDO...
>> adapting this answer
>>The short answer is yes, yes there is a way to get around mysql_real_escape_string().
所以这个问题产生的过程是
1)用了会 fallback 的 sql 语句,PDO 认为不能进行 MySQL native prepare,进行本地摸你
2)PHP 调用 mysql_real_escape_string()
3)mysql_real_escape_string 在某些版本下有 BUG,会导致过滤失败
4)PDO 直接把拼接的 SQL 发过去了
5)被注入了
另外,PHP 官方已经写得很清楚了,设置 charset 的时候,要在初始化的时候进行。你错误的使用了 PDO,导致 PDO 本身失效,能怪谁呢?
>
https://secure.php.net/manual/zh/ref.pdo-mysql.connection.php