为什么这个MySQLI预处理语句允许SQL注入?

Pau*_*rel 5 php sql mysqli code-injection prepared-statement

当我今天教学生如何防止SQL注入时,我有点尴尬.在专业项目中,我使用预准备语句/参数化查询作为防止SQL注入的一层(尽管我从未专业地使用过mySQL).理论上,我认为使用预准备语句时SQL注入是不可能的.

但后来这起作用......

$Search = $_GET['s'];
$stmt = $mysqli->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("i", $Search);
$stmt->execute();
$Results = $stmt->get_result();
Run Code Online (Sandbox Code Playgroud)

如果我传递参数"?s = 1 OR 1 = 1",那么我可以获得所有产品的完整列表.我仍然无法在最后插入另一个查询,但我很困惑为什么在mysql/php中可以使用这种类型的基本SQL注入.我假设参数"1 OR 1 = 1"将被拒绝,因为它不是数字(显然我可以运行该数字检查......).

任何人都可以解释为什么这个工作,以及我不明白php/mysql中准备好的语句?

我的学校电脑有一个开箱即用的Zend WAMP安装btw.

编辑:这是导致我混淆的字符串值:

$Search = "1 OR 1=1";
Run Code Online (Sandbox Code Playgroud)

Iły*_*sov 8

没关系,这里没有任何类型的SQL注入,你没有看到所有产品的列表(至少你提供的代码无法显示)

你不需要转换为int,让我们深入了解bind_param实际做的事情:

它有字符串"i",表示1个integer参数

你是从$ _GET那里传递价值的 string

bind_param尝试将String转换为int,所以检查这个php代码:

echo intval('a', 10); // output 0
echo intval('1a', 10); // output 1
echo intval('12a', 10); // output 12
echo intval('b1', 10); // output 0
echo intval('1 or 1=1', 10); // output 1
echo intval("?s=1 OR 1=1", 10); // output 0
Run Code Online (Sandbox Code Playgroud)

所以,你输出id = 1的产品,也许你有一些?


use*_*035 7

我试图重现你的情况,但不能.

数据库

CREATE TABLE `Document` (
  `DataID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Description` varchar(50) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`DataID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

INSERT INTO `Document` VALUES (1,'BI8392');
INSERT INTO `Document` VALUES (2,'HE8492');
INSERT INTO `Document` VALUES (3,'HE8493');
INSERT INTO `Document` VALUES (4,'HE8490');
Run Code Online (Sandbox Code Playgroud)

<?php
$host = "localhost";
$passwd = "";
$user = "user";
$bdd = "test";

$conn = mysqli_connect( $host, $user, $passwd, $bdd);
mysqli_set_charset($conn, "utf8");

if (!$conn) {
   printf('Error connecting to mysql. Error code: ', mysqli_connect_error());
   exit;
}

$sql = "SELECT * FROM Document WHERE DataID = ?";
if ($stmt = $conn->prepare($sql)) {

    $param = "2 OR 1=1";
    $stmt->bind_param("i", $param);
    $stmt->execute();
    $results = $stmt->get_result();
    $data = mysqli_fetch_all($results);

    var_dump($data);
}
Run Code Online (Sandbox Code Playgroud)

产量

array(1) {
  [0]=>
  array(2) {
    [0]=>
    int(2)
    [1]=>
    string(6) "HE8492"
  }
}
Run Code Online (Sandbox Code Playgroud)

似乎,1 = 1条件被忽略.