Текуща ситуация: PHP2Shell. Две критични уязвимости в PHP (CVSS 9,2) позволяват злонамерен код без вход. Корекции от 21.10.2026 г.Какво да направите сега →

PHP и бази данни: PDO и mysqli

PHP работи с бази данни през PDO или mysqli. Тук виждате разликите, сигурните заявки с подготвени заявки и какво да направите с данните за достъп до базата след инцидент със сървъра.

Актуалност 5 мин. четенеЗнания за PHP

Накратко: PHP достъпва базите данни през два разпространени интерфейса: PDO (PHP Data Objects) работи с много системи за бази данни през единен интерфейс, mysqli е съобразен с MySQL и MariaDB. И с двата подготвените заявки, т.е. заявки със заместители, надеждно защитават от SQL инжекции. От PHP 8.0 (PDO), респективно 8.1 (mysqli), и двата съобщават по подразбиране грешките като изключение.

Как PHP общува с бази данни

Почти всяко PHP приложение съхранява съдържанието си в база данни: страници, поръчки, потребителски акаунти, настройки. За целта PHP скриптът установява връзка, изпраща заявка на езика SQL и обработва резултата. Данните за достъп най-често стоят в конфигурационен файл на същия сървър.

За управлението на фирмата това е важно, защото базата данни най-често съдържа най-ценните данни на фирмата. Който може да изпълнява код на уеб сървъра, по правило може да прочете и конфигурационния файл и с тези данни за достъп да достъпи базата данни.

PDO и mysqli в сравнение

Характеристика PDO mysqli
Бази данни много, чрез драйвери като PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI MySQL и MariaDB
Заместители именувани (:name) и позиционни (?) позиционни (?)
Стил обектно-ориентиран обектно-ориентиран и процедурен
Грешки като изключение по подразбиране от PHP 8.0.0 по подразбиране от PHP 8.1.0
Кратка форма за заявки с параметри prepare() и execute() с масив execute_query() от PHP 8.2.0

На практика често решава framework-ът или CMS. Много от тях носят собствен слой за бази данни, който вътрешно ползва PDO или mysqli. Който поема приложение, може с обикновено търсене в изходния код да установи кой интерфейс се използва и къде възникват заявките:

# Къде приложението установява връзки, къде възникват заявки?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50

Намерените места с ->query( не са автоматично несигурни. Заслужават обаче втори поглед, защото там стойности могат да попаднат директно в SQL текста, вместо да се предават през заместители. Особено по-старите проекти смесват двата стила и проверката си струва преди всяка по-голяма актуализация.

Подготвени заявки: най-важният шаблон

При подготвената заявка заявката се изпраща на базата данни със заместители, а стойностите се предават отделно. Според ръководството на PHP това защитава от SQL инжекции, когато всички потребителски въведени данни минават през заместители.

<?php
declare(strict_types=1);

$pdo = new PDO(
    'mysql:host=localhost;dbname=shop;charset=utf8mb4',
    $dbUser,
    $dbPass,
    [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);

$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE plz = :plz AND aktiv = :aktiv');
$stmt->execute(['plz' => $plz, 'aktiv' => 1]);

foreach ($stmt as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}

Същото с mysqli в краткия вариант, който съществува от PHP 8.2:

<?php
$db = new mysqli('localhost', $dbUser, $dbPass, 'shop');
$ergebnis = $db->execute_query('SELECT id, name FROM kunden WHERE plz = ?', [$plz]);

foreach ($ergebnis as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}

Разработчиците трябва да знаят две граници. Заместителите не бива да стоят в кавички; при търсене с LIKE символите за заместване % принадлежат в предаваната стойност. И заместителите заменят само стойности, не имена на таблици или колони. Как да се решават сигурно такива специални случаи, показва наръчникът Предотвратяване на SQL инжекции в PHP.

Обработка на грешки: изключения вместо тихи грешки

Преди двата интерфейса работеха по подразбиране тихо: неуспешна заявка връщаше false и който не го проверяваше, продължаваше да работи с празни данни. Това се е променило:

  • PDO: От PHP 8.0.0 PDO::ERRMODE_EXCEPTION е стойността по подразбиране. Грешките хвърлят PDOException.
  • mysqli: От PHP 8.1.0 съобщаването на грешки е зададено на MYSQLI_REPORT_ERROR и MYSQLI_REPORT_STRICT. Грешките хвърлят mysqli_sql_exception; преди съобщаването беше изключено.

За сигурността това означава: изключенията трябва да се прихващат и записват в дневник, но никога не бива да попадат в браузъра със SQL текст, имена на таблици или данни за достъп. Как да се раздели това чисто, описва страницата Грешки и изключения в PHP.

Правилно предоставяне на данни за достъп и права

Базата данни е защитена толкова добре, колкото са защитени нейните данни за достъп. Доказали са се следните правила:

  1. Отделен потребител за всяко приложение: Никога не ползвайте администратора на базата данни за уебсайта.
  2. Само нужните права: Един уебсайт обикновено се нуждае от четене, запис, промяна и изтриване в собствената си база данни, но не и от права върху други бази данни или сървърни функции.
  3. Без отдалечена връзка без причина: Базата данни трябва да е достъпна само от уеб сървъра, а не от интернет.
  4. Данни за достъп извън уеб корена: Конфигурационните файлове и .env файловете не бива да са достъпни по URL. Повече по темата в статията Защита на данните за достъп и .env файловете.
  5. Криптирана връзка при разделени сървъри: Ако базата данни е на друг компютър, връзката трябва да е криптирана, за да не минават данните за достъп и съдържанието през мрежата в открит текст.
  6. Отделни достъпи за поддръжка: Архивирането, справките и администраторите получават отделни потребители. Така в дневника може да се проследи кой какво е направил и един достъп може да се блокира, без да се пречи на уебсайта.

Бази данни, PHP2Shell и най-лошият случай

PHP2Shell не засяга самата база данни, а интерпретатора на PHP: CVE-2026-109618 и CVE-2026-109619 позволяват изпълнение на злонамерен код без влизане в системата. Ако това успее, кодът се изпълнява с правата на PHP процеса и така по правило може да прочете конфигурационния файл с данните за достъп до базата данни. Подготвените заявки срещу това не помагат, защото атаката изобщо не минава през SQL заявка.

Задължителни са затова актуализацията до PHP 8.5.12, 8.4.27, 8.3.36 или 8.2.35 и рестартирането на всички PHP процеси. Ако има данни за успешна атака, към това спадат нови данни за достъп до базата данни, проверка на базата данни за вмъкнато съдържание и оценка на задължението за уведомяване по ОРЗД. Тук е смислен структуриран отговор на инциденти (Incident Response).

Съвет

Сменяйте паролите на базата данни едва след почистването на сървъра. Докато работи злонамерен код, той може да прочете отново и новите данни за достъп.

Как помага PHP SOS конкретно?

  • Проверяваме как Вашето приложение достъпва базата данни и дали потребителите, правата и мрежовият достъп съответстват на необходимия минимум.
  • Контролираме дали конфигурационните файлове и файловете с данни за достъп лежат извън уеб корена и не са публично достъпни.
  • След инцидент подновяваме данните за достъп в правилния ред и проверяваме базата данни за вмъкнат код.
  • Документираме резултатите така, че длъжностните лица по защита на данните и застрахователите да могат да ги проследят.

Често задавани въпроси

PDO или mysqli да използвам?

За нови проекти PDO обикновено е по-гъвкавият избор, защото работи с много бази данни през един и същ интерфейс. mysqli е смислен, ако ползвате изключително MySQL или MariaDB и се нуждаете от техните специални функции. И двете са сигурни, ако подготвените заявки се прилагат последователно.

Хвърля ли PDO автоматично изключения при грешки?

Да, от PHP 8.0.0 PDO::ERRMODE_EXCEPTION е стойността по подразбиране. Преди това режимът беше тих и грешките се извличаха само чрез errorCode() и errorInfo(). По-старите приложения често още задават режима изрично.

Могат ли заместителите да заменят и имена на таблици или колони?

Не. Заместителите стоят само за стойности. Имената на таблици и колони, например за сортиране, трябва да се проверят спрямо фиксиран списък с разрешени имена, преди да бъдат вмъкнати в заявката.

Трябва ли след PHP2Shell да сменя паролата на базата данни?

Самата актуализация не го изисква. Ако обаче има данни, че сървърът е бил компрометиран, всички данни за достъп в конфигурационните файлове се смятат за известни. Тогава трябва да ги подновите след почистването.

Източници

Незабавен контакт

Всеки час има значение. Пишете ни сега.

Опишете накратко системата, версията на PHP и какво сте забелязали. Ние се свързваме с Вас, уточняваме ситуацията и работим отдалечено, докато инцидентът бъде приключен и документиран.

Незабавна помощ