PHP:使用准备好的语句并防止SQL注入与转义
我确实理解,准备好的语句是针对SQL注入寻求保护的最终方法。但是,它们提供的覆盖范围有限;例如,在我让用户决定如何按操作排序的情况下(即,是ASC还是DESC?等),我没有得到准备好的语句的覆盖 我知道我可以将用户输入映射到预定义的白名单。但是,这只有在事先可以创建或完全猜测白名单的情况下才可能实现 例如,在我上面提到的情况下(ASC或DESC),可以很容易地根据接受值列表映射和验证。但是,难道不存在无法对照白名单验证SQL语句部分的情况吗 如果存在这种情况,那么推荐的方法是什么 如果我要使用底层数据库的内置转义实用程序(例如mysqL的mysqL\u real\u escape\u string)全面转义用户输入,我会在哪里失败 我问这个问题的前提是我总是用引号来构造sql语句——即使是整数 让我们看一看下面的例子并思考一下PHP:使用准备好的语句并防止SQL注入与转义,php,prepared-statement,sql-injection,mysql-real-escape-string,Php,Prepared Statement,Sql Injection,Mysql Real Escape String,我确实理解,准备好的语句是针对SQL注入寻求保护的最终方法。但是,它们提供的覆盖范围有限;例如,在我让用户决定如何按操作排序的情况下(即,是ASC还是DESC?等),我没有得到准备好的语句的覆盖 我知道我可以将用户输入映射到预定义的白名单。但是,这只有在事先可以创建或完全猜测白名单的情况下才可能实现 例如,在我上面提到的情况下(ASC或DESC),可以很容易地根据接受值列表映射和验证。但是,难道不存在无法对照白名单验证SQL语句部分的情况吗 如果存在这种情况,那么推荐的方法是什么 如果我要使用底
select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}
假设所有变量都是用户提供的
如果我使用mysql\u real\u escape\u string来处理上述SQL中的所有变量(而不是使用只覆盖了我一半的预处理语句,迫使我为另一半列出白名单,这是无法帮助的),那么它不是同样安全(并且更容易编码)?如果不是,在哪个输入场景中转义实用程序会失败
$fields = mysql_escape($fields);
$table = mysql_escape($table);
$age = mysql_escape($age);
$orderby_pref = mysql_escape($orderby_pref);
select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}
你可以使用PDO,你的生活会变得更轻松…:
# Order
switch(strtoupper($Order)){
default:
case 'ASC':
$Order = 'ASC';
break;
case 'DESC':
$Order = 'DESC';
break;
}
# ID
$ID = 39;
$Username = 'David';
# Query
$Query = $this->DB->Main->prepare('SELECT * FROM Table WHERE ID = :ID AND Username = :Username ORDER BY HellBob '.$Order);
$Query->bindValue(':ID', $ID, PDO::PARAM_INT);
$Query->bindValue(':Username', $Username, PDO::PARAM_STR);
# All good ?
if(!$Query->execute()){
exit('Error');
}
// Results
$Row = $Query->fetch(PDO::FETCH_ASSOC);
您不必担心引号或SQL注入。您可以使用您提到的简单的“白名单”将变量放入查询。无论您使用的是预先准备好的语句还是
mysql
转义函数,对于表名或列名等内容,您始终需要使用白名单
问题是表名和列名不能用单引号或双引号引起来,因此如果您使用一个函数专门引用这些字符(当然还有更多的字符…),那么它对表名没有任何作用
考虑表名my_表;从mysql中删除*;从我的表格中选择*
。这个字符串中的任何内容都不会被mysql的转义函数转义,但它肯定是一个您希望对照白名单检查的字符串
除此之外,
mysql
转义函数在字符集方面存在问题,这些字符集可能会使它们变得无用,因此您最好使用预先准备好的语句。您忘记了排序字段;-)这并不能真正回答问题,因为您已经在查询中硬编码了表名、列名和排序顺序列。然后,您可以使用白名单来编写表名。除了白名单之外,没有其他安全的方法。向上投票是因为您知道并关心sql注入(与大多数人在PHP标签中提问相反),动态sql和向查询中添加值之间存在差异。绑定参数或字符串连接(加上转义)都可以用于添加值。动态SQL需要白名单可接受的语法。因此,可以使用regex、map或switch语句来添加DESC
或ORDER
和其他限定符。不过,存储过程将是一个冗长的选择;从mysql中删除*;从my_表中选择*可以很好地确定MYSQL_转义方法失败的原因。。。。因此,简单地说,SQL注入保护的唯一替代方案(对于准备好的语句或db的转义实用程序没有帮助的部分)是使用白名单方法。这个结论正确吗?