Как предотвратить SQL-инъекцию в PHP?
Если вводимые пользователем данные вставляются в SQL-запрос без изменений, тогда приложение становится уязвимым для SQL-инъекции, как показано в следующем примере:
$unsafe_variable = $_POST[‘user_input’];
mysql_query(«INSERT INTO `table` (`column`) VALUES (‘$unsafe_variable’)»);
Это происходит потому, что пользователь может ввести что-то вроде value’); DROP TABLE table;— , и запрос будет выглядеть следующим образом:
INSERT INTO `table` (`column`) VALUES(‘value’); DROP TABLE table;—‘)
Что можно сделать, чтобы этого избежать?
Ответ 1
- Использование PDO (для любого поддерживаемого драйвера базы данных):
- Использовать MySQLi (для MySQL):
Правильная настройка подключения
Обратите внимание, что при использовании PDO для доступа к базе данных MySQL подготовленые операторы по умолчанию не используются . Чтобы исправить это, вам нужно включить эмуляцию этих операторов. Пример создания соединения с использованием PDO:
$dbConnection = new PDO(‘mysql:dbname=dbtest; host=127.0.0.1; charset=utf8’, ‘user’, ‘password’);
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
В приведенном выше примере активация режима ошибки не является строго обязательной, но рекомендуется использовать ее . Таким образом, скрипт не остановится, на критической ошибке, когда что-то пойдет не так. И это дает разработчику шанс на перехват любой ошибки, которую бросит PDOException s.
Однако обязательной является первая setAttribute() строка, которая сообщает PDO отключить эмулируемые операторы и использовать подготовленые операторы. Это гарантирует, что оператор и его значения не будут проанализированы PHP перед его отправкой на сервер MySQL (что не дает возможному злоумышленнику возможности внедрить вредоносный SQL).
Хотя вы можете установить charset в параметрах конструктора, важно отметить, что «старые» версии PHP (до 5.3.6) игнорировали этот параметр в DSN.
Объяснение
Указав параметры (либо именованный параметр, как name в приведенном выше примере), вы сообщаете движку базы данных, где вы хотите выполнить фильтрацию запроса. Затем, когда вы вызываете execute , подготовленный оператор объединяется с указанными вами значениями параметров.
Здесь важно то, что значения параметров объединяются со скомпилированным оператором, а не со строкой SQL. SQL инъекция работает путем ложного сценария, который включает вредоносные строки при создании SQL для отправки в базу данных. Таким образом, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск получить то, чего не планировали.
Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут обрабатываться просто как строки (хотя ядро базы данных может выполнять некоторую оптимизацию, поэтому параметры, конечно же, могут оказаться числами). В приведенном выше примере, если $name переменная содержит ‘Ваня’; DELETE FROM employees Результатом, будет просто поиск строки «‘Ваня’; DELETE FROM employees» , и вы не удалите таблицу.
Еще одно преимущество использования подготовленных операторов заключается в том, что если вы выполняете один и тот же оператор много раз в одном сеансе, он будет проанализирован и скомпилирован только один раз, что даст вам некоторый прирост скорости.
Да, и поскольку вы спросили, как это сделать для оператора INSERT INTO, вот пример (с использованием PDO):
$preparedStatement = $db->prepare(‘INSERT INTO table (column) VALUES (:column)’);
$preparedStatement->execute([ ‘column’ => $unsafeValue ]);
Можно ли использовать подготовленные операторы для динамических запросов?
Хотя вы по-прежнему можете использовать подготовленные операторы для параметров запроса, структура самого динамического запроса и его некоторые функции не могут быть параметризованы. Для этих сценариев лучше всего использовать фильтр явного списка, который ограничивает возможные значения, например:
// Явный список
// $dir может быть ‘DESC’ или ‘ASC’
if (empty($dir) || $dir !== ‘DESC’)
$dir = ‘ASC’;
>
Ответ 2
- Если вы хотите изменить структуру SQL на основе пользовательского ввода, параметризованные запросы не помогут, в этом случае необходимо экранировать запрос с помощью mysql_real_escape_string . Лучше передать вводимые пользователем данные через явный список, чтобы обеспечить пропуск только «безопасных» значений.
- Если вы используете целые числа из пользовательского ввода в условии и применяете функцию mysql_real_escape_string , вы столкнетесь с проблемой, потому что целые числа не будут заключаться в кавычки, и вы не можете быть уверены в корректности формирования запроса.
Ответ 3
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.