Как предотвратить SQL инъекции в PHP

27 января 2019
3518
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.
ОК