Поскольку я преподавал студентам, как предотвратить внедрение 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();
Если я передаю параметр «? S = 1 ИЛИ 1 = 1», тогда я могу получить полный список всех продуктов. Я все еще не могу вставить другой запрос в конце, но я смущен тем, почему этот тип базовой инъекции SQL возможен в mysql / php. Я предположил, что параметр «1 ИЛИ 1 = 1» будет отклонен, потому что он не является числовым (очевидно, я мог бы выполнить эту числовую проверку …).
Может ли кто-нибудь объяснить, почему это работает, и что я не понимаю о подготовленных инструкциях в php / mysql?
У моего школьного компьютера есть готовая установка Zend WAMP.
EDIT: это строковое значение, вызывающее мою путаницу:
$Search = "1 OR 1=1";
Все в порядке, никакой какой-либо инъекции 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
поэтому вы выводите продукты с id = 1, возможно, у вас есть некоторые из них?
Я попытался воспроизвести ваше дело, но не смог.
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');
<?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); }
array(1) { [0]=> array(2) { [0]=> int(2) [1]=> string(6) "HE8492" } }
Кажется, что условие 1 = 1 было проигнорировано.