SQL注入和预处理语句,什么时候会过度使用


SQL injection and prepared statement, when does it get overkill?

我读了很多关于sql注入,我已经使用mysqli准备语句一年多了。我更接近我的问题是这个为什么这个mysql准备语句允许SQL注入?

现在,我想创建一个函数来运行基于用户搜索条件的查询。我使用这个,所以我可以使用许多不同的标准。

这里有一个简单的例子,这样你就可以理解我的问题了:假设我们有两个表,一个有轮胎,另一个有轮子。
CREATE TABLE IF NOT EXISTS `wheels` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `brand` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `size` int(11) NOT NULL,
  `price` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `brand` (`brand`),
  KEY `size` (`size`),
  KEY `price` (`price`)
);
CREATE TABLE IF NOT EXISTS `tires` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `brand` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `size` int(11) NOT NULL,
  `price` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `brand` (`brand`),
  KEY `size` (`size`),
  KEY `price` (`price`)
);

现在我们有一个表单让用户进行搜索

<form method='post' ...>
  Looking for : <select name='item'>
    <option value='tires'>Tires</option>
    <option value='wheels'>Wheels</option>
  </select>
  Search by : <select name='type'>
    <option value='size'>Size</option>
    <option value='price'>Maximum price</option>
  </select>
  <input type='text' name='criteria' />
</form>

现在处理请求的php看起来像这样:

$item=filter_input(INPUT_POST,'item',FILTER_SANITIZE_STRING);
$type=filter_input(INPUT_POST,'type',FILTER_SANITIZE_STRING);
$criteria=filter_input(INPUT_POST,'criteria',FILTER_SANITIZE_NUMBER_INT);
function build_query($item,$type,$criteria){
  switch($item){
    case 'tires': $table='tires'; break;
    case 'wheels': $table='wheels'; break;
    defaults: /*error handling : bad search criteria*/ break;
  }
  switch($type){
    case 'size': $field='size'; $operator='='; break;
    case 'price': $field='price'; $operator='<='; break;
    defaults: /*error handling : bad search criteria*/ break;
  }
  $value=intval($criteria);
  $sql= ....
  //Do the rest of sqli magic here and return the results.
}

请注意,只有$标准(成为$值)不是"硬编码"并从搜索表单发送到DB。所以问题将是:如果$表,$字段和$操作符变量是从我的php内部代码,是必要的绑定他们,以及?

换句话说:

这是不是太夸张了?

$sql="SELECT * FROM ? WHERE ???"; 
$stmt->bind_param('sssi',$table,$field,$operator,$value);

AND/OR这是否足够?

$sql="SELECT * FROM ".$table." WHERE ".$field.$operator."?";
$stmt->bind_param('i',$value);

如前所述,这是一个简化的示例,以便您更好地理解问题

是的,使用PDO你将走得更远。PDO仅用于参数,而不用于表或操作符。使用第二个查询

http://php.net/manual/en/pdostatement.bindparam.php不表示表和操作符是允许的,我记得之前测试过,发现它们是不允许的。

将PHP变量绑定到相应的命名号或问号的SQL语句中的占位符声明。与PDOStatement::bindValue()不同,变量被绑定为推荐信,只会在那时进行评估PDOStatement::execute()被调用

大多数参数都是输入参数,也就是说,参数是以只读方式使用,以构建查询。有些司机支持调用返回数据作为输出的存储过程参数,有些也作为输入/输出参数发送进来数据和更新接收它。