Как предотвратить SQL инъекции в PHP
Если пользовательский ввод не обрабатывается и не проверяется должным образом, то ваш сайт становится уязвим к SQL инъекциям PHP (SQL injection).
Предположим, у вас есть код:
$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;--')
Что можно сделать, чтобы этого не случилось?
Используйте подготовленные операторы (prepared statement) и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не сможет внедрить вредоносный SQL.
У вас есть два варианта для достижения этой цели:
-
Использование PDO (для любого поддерживаемого драйвера базы данных):
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) { // do something with $row }
-
Использование MySQLi (для MySQL):
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row }
Если вы подключаетесь к базе данных, отличной от MySQL, существует вторая опция для драйвера, к которой вы можете обратиться (например, pg_prepare()
и pg_execute()
в PostgreSQL). PDO - это универсальный вариант.
Правильная настройка соединения
Обратите внимание, что при использовании PDO
для доступа к базе данных MySQL реально подготовленные операторы не используются по умолчанию . Чтобы это исправить, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием PDO:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
В приведенном выше примере использовать “ERRMODE” не является необходимым, но рекомендуется добавить его . Таким образом, скрипт не остановится на Fatal Error
когда что-то пойдет не так. И это дает разработчику возможность отловить ошибки.
Однако обязательной является первая строка (setAttribute()
), которая указывает PDO отключить эмулированные подготовленные операторы и использовать реально подготовленные операторы.
Это гарантирует, что оператор и значения не будут проанализированы PHP перед отправкой его в MySQL (не давая возможности злоумышленнику внедрить вредоносный SQL).
Хотя вы можете установить charset
в параметрах конструктора, важно отметить, что «старые» версии PHP (<5.3.6) игнорировали параметр charset в DSN.
Что происходит под капотом
Передаваемый вами запрос SQL prepare
анализируется и компилируется сервером базы данных. Задавая параметры ( ?
или именованный параметр как в примере выше мы использовали :name
), вы указываете как вы хотите фильтровать запрос. Затем при вызове execute
подготовленный оператор объединяется с указанными вами параметрами.
Здесь важно то, что значения параметров объединяются с скомпилированным оператором, а не строкой SQL. Инъекция SQL работает путем обмана скрипта при передаче SQL запроса в базу данных. Таким образом, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск.
Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут просто обрабатываться как строки (хотя ядро базы данных может выполнять некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться числами).
В приведенном выше примере, если переменная $name
содержит 'Sarah'; DELETE FROM employees
, это будет просто поиск строки "'Sarah'; DELETE FROM employees"
, и вы не получите пустую таблицу .
Еще одним преимуществом использования подготовленных операторов является то, что если вы выполняете один и тот же оператор много раз в одной и той же сессии, он будет проанализирован и скомпилирован только один раз, что даст вам некоторое увеличение скорости работы.
Теперь вы знаете как сделать защиту от sql инъекций PHP на вашем сайте.
Рекомендуемые статьи:
- Как изменить версию PHP на сервере с Debian 10
- PhpMyAdmin — как создать пользователя и базу данных
- Wordpress — как отключить управление сайтом через xmlrpc
- Несколько причин медленной работы сайта на примере Wordpress
- Wordpress - смена домена сайта при помощи wp-cli
- Когда использовать index.php, а когда index.html
- PHP. Как удалить элемент из массива
- Дата и время в PHP
- PHP. Различия между Fast-CGI, CGI, Mod-PHP, SuPHP, PHP-FPM
- Простой пример кода на языке PHP
- PHP. Проверка содержит ли строка определенное слово
- Как установить Linux, Apache, MySQL, PHP (LAMP) в Ubuntu 18.04
- Как настроить отображение ошибок в PHP
- Несколько трюков и секретов PHP