SQL 注入和准备好的语句,什么时候变得矫枉过正?
SQL injection and prepared statement, when does it get overkill?
我已经阅读了很多关于 sql 注入的文章并且我已经使用我的sql我准备好的声明一年多了。我越接近我的问题就是这个 Why does this MySQLI prepared statement allow SQL injection?
现在,我想创建一个函数来 运行 根据用户的搜索条件进行查询。我正在使用它,所以我可以使用很多不同的标准。
这里是一个简化的例子,所以你可以绕过我的问题:
假设我们有两个 table,一个有轮胎,一个有轮子。
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.
}
请注意,只有 $criteria(成为 $value)不是 'hard coded' 并从搜索表单发送到数据库。
所以问题是: 如果 $table、$field 和 $operator 变量来自我的 php 内部代码,是否也有必要绑定它们?
换句话说:
这是矫枉过正吗?
$sql="SELECT * FROM ? WHERE ???";
$stmt->bind_param('sssi',$table,$field,$operator,$value);
和/或这就足够了吗?
$sql="SELECT * FROM ".$table." WHERE ".$field.$operator."?";
$stmt->bind_param('i',$value);
如前所述,这是一个简化的示例,以便您更好地理解问题。
是的,您将使用 PDO 走得很远。 PDO 仅用于参数,而不用于表或运算符。使用您的第二个查询。
http://php.net/manual/en/pdostatement.bindparam.php 不表示允许表和运算符,我记得前一段时间测试过,发现它们不是。
Binds a PHP variable to a corresponding named or question mark
placeholder in the SQL statement that was used to prepare the
statement. Unlike PDOStatement::bindValue(), the variable is bound as
a reference and will only be evaluated at the time that
PDOStatement::execute() is called.
Most parameters are input parameters, that is, parameters that are
used in a read-only fashion to build up the query. Some drivers
support the invocation of stored procedures that return data as output
parameters, and some also as input/output parameters that both send in
data and are updated to receive it.
我已经阅读了很多关于 sql 注入的文章并且我已经使用我的sql我准备好的声明一年多了。我越接近我的问题就是这个 Why does this MySQLI prepared statement allow SQL injection?
现在,我想创建一个函数来 运行 根据用户的搜索条件进行查询。我正在使用它,所以我可以使用很多不同的标准。
这里是一个简化的例子,所以你可以绕过我的问题: 假设我们有两个 table,一个有轮胎,一个有轮子。
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.
}
请注意,只有 $criteria(成为 $value)不是 'hard coded' 并从搜索表单发送到数据库。 所以问题是: 如果 $table、$field 和 $operator 变量来自我的 php 内部代码,是否也有必要绑定它们?
换句话说:
这是矫枉过正吗?
$sql="SELECT * FROM ? WHERE ???";
$stmt->bind_param('sssi',$table,$field,$operator,$value);
和/或这就足够了吗?
$sql="SELECT * FROM ".$table." WHERE ".$field.$operator."?";
$stmt->bind_param('i',$value);
如前所述,这是一个简化的示例,以便您更好地理解问题。
是的,您将使用 PDO 走得很远。 PDO 仅用于参数,而不用于表或运算符。使用您的第二个查询。
http://php.net/manual/en/pdostatement.bindparam.php 不表示允许表和运算符,我记得前一段时间测试过,发现它们不是。
Binds a PHP variable to a corresponding named or question mark placeholder in the SQL statement that was used to prepare the statement. Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
Most parameters are input parameters, that is, parameters that are used in a read-only fashion to build up the query. Some drivers support the invocation of stored procedures that return data as output parameters, and some also as input/output parameters that both send in data and are updated to receive it.