Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як налаштувати шифроване з'єднання між Laravel і MySQL і перевірити сертифікат сервера?

Без TLS запити, результати й (залежно від плагіна) облікові дані передаються мережею у відкритому вигляді. Для бази на тому ж хості через сокет це не проблема; для бази в іншій мережі, хмарі чи між дата-центрами - обов'язково.

Сторона сервера. MySQL 8 при першому старті сам генерує самопідписані сертифікати й вмикає TLS за замовчуванням: клієнт, що підтримує TLS, використає його. Але:

  • самопідписаний сертифікат захищає від прослуховування, але не від підміни сервера (атака посередника), якщо клієнт його не перевіряє;
  • клієнт може підключитися й без TLS, якщо сервер цього не забороняє.

Заборонити незашифровані підключення:

SET PERSIST require_secure_transport = ON;   -- для всіх, крім сокета

-- або для окремого облікового запису
ALTER USER 'app'@'%' REQUIRE SSL;
ALTER USER 'app'@'%' REQUIRE X509;           -- ще й клієнтський сертифікат

Сторона Laravel. Підключення налаштовується через опції PDO в config/database.php:

'options' => extension_loaded('pdo_mysql') ? array_filter([
    (PHP_VERSION_ID >= 80500 ? Pdo\Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
    (PHP_VERSION_ID >= 80500 ? Pdo\Mysql::ATTR_SSL_VERIFY_SERVER_CERT : PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT) => true,
]) : [],
  • ATTR_SSL_CA - сертифікат центру сертифікації, яким підписано сертифікат сервера. У хмарних провайдерів (RDS, Cloud SQL, PlanetScale) це їхній публічний CA-бандл;
  • ATTR_SSL_VERIFY_SERVER_CERT = true - перевіряти сертифікат сервера. Без цього TLS є, але підключитися можна й до підставного сервера;
  • для взаємної автентифікації - ATTR_SSL_CERT і ATTR_SSL_KEY (клієнтські сертифікат і ключ).

У PHP 8.5 константи PDO::MYSQL_ATTR_* оголошено застарілими на користь Pdo\Mysql::ATTR_* - звідси перевірка версії в типовому конфігу Laravel.

Як перевірити, що з'єднання справді зашифроване:

SHOW SESSION STATUS LIKE 'Ssl_cipher';   -- непорожнє значення = TLS
SHOW SESSION STATUS LIKE 'Ssl_version';  -- TLSv1.3 / TLSv1.2

З Laravel - тим самим запитом: DB::select("SHOW SESSION STATUS LIKE 'Ssl_cipher'"). А які з усіх поточних підключень ідуть без шифрування, показує performance_schema.status_by_thread зі змінною Ssl_cipher для кожного потоку.

Для консольного клієнта аналогічний рівень дає --ssl-mode=VERIFY_IDENTITY (перевіряє і ланцюжок, і що ім'я хоста збігається з сертифікатом), а --ssl-mode=REQUIRED лише шифрує без перевірки.

Ротація сертифікатів у MySQL 8 можлива без перезапуску: замінити файли й виконати ALTER INSTANCE RELOAD TLS.

Докладніше в документації: Шифровані з'єднання

Схожі питання