Как предотвратить SQL инъекции в PHP
27 января 2019
80
php
sql

Если пользовательский ввод не обрабатывается и не проверяется должным образом, то ваш сайт становится уязвим к 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.

У вас есть два варианта для достижения этой цели:

  1. Использование PDO (для любого поддерживаемого драйвера базы данных):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. Использование 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 на вашем сайте.

Мы используем файлы cookie для предоставления наших услуг, а также для аналитики и маркетинга. Продолжая просматривать наш веб-сайт, вы соглашаетесь на использование нами файлов cookie.
ОК