Avatar ·

Как безопасно хранить пароли базы данных в PHP-приложении?

Всем привет! Я новичок в PHP и разрабатываю небольшой сайт с подключением к MySQL. Сейчас я храню логин и пароль от базы данных прямо в коде, в файле `config.php`: ```php >>

Правильный подход: переменные окружения и файлы конфигурации вне document root

Проблема, которую вы описали, действительно критична. Хранение паролей в коде — одна из самых частых уязвимостей начинающих разработчиков. Вот профессиональное решение, которое используется в индустрии.

Шаг 1. Никогда не храните секреты в репозитории

Создайте файл .env в корне проекта (вне публичной директории сервера). Добавьте его в .gitignore:

# .gitignore
.env
.env.local

Шаг 2. Структура .env файла

DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=myapp_user
DB_PASSWORD=SuperSecretP@ssw0rd!

Шаг 3. Загрузка .env через библиотеку (например, vlucas/phpdotenv)

Установите через Composer:

composer require vlucas/phpdotenv

Создайте файл bootstrap.php (загружается первым):

<?php
require_once __DIR__ . '/vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// Теперь можно использовать переменные окружения
$host = $_ENV['DB_HOST'];
$dbname = $_ENV['DB_DATABASE'];
$username = $_ENV['DB_USERNAME'];
$password = $_ENV['DB_PASSWORD'];

$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

Шаг 4. Альтернатива без библиотек — свой загрузчик

Если не хотите использовать Composer, напишите простую функцию:

<?php
function loadEnv(string $path): void {
    if (!file_exists($path)) {
        throw new RuntimeException('.env file not found');
    }
    
    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (str_starts_with(trim($line), '#')) continue; // комментарии
        
        if (str_contains($line, '=')) {
            [$key, $value] = explode('=', $line, 2);
            $key = trim($key);
            $value = trim($value);
            
            // Убираем кавычки, если есть
            if (in_array($value[0] ?? '', ['"', "'"])) {
                $value = substr($value, 1, -1);
            }
            
            putenv("$key=$value");
            $_ENV[$key] = $value;
        }
    }
}

// Использование
loadEnv(__DIR__ . '/.env');
$password = getenv('DB_PASSWORD'); // или $_ENV['DB_PASSWORD']

Шаг 5. Дополнительные меры безопасности

  • Разместите .env вне document root — на один уровень выше папки public/ или www/.
  • Используйте разные пароли для разработки и продакшена — никогда не копируйте продакшен-пароли в локальный .env.
  • Ограничьте права доступа к файлу — chmod 600 .env (чтение только владельцем).
  • Для продакшена используйте реальные переменные окружения сервера, а не файл .env (например, через Docker secrets или панель хостинга).

Почему это безопасно?

Даже если злоумышленник получит доступ к вашему PHP-коду (через File Inclusion или бэкап), он не увидит пароль — он хранится отдельно. А если вы случайно зальёте код на GitHub, файл .env будет проигнорирован благодаря .gitignore.

Важно: Никогда не используйте шифрование паролей БД — это даёт ложное чувство безопасности. Ключ шифрования придётся хранить там же, где и зашифрованные данные, что бессмысленно. Вместо этого используйте описанный выше подход с переменными окружения.

<<>>

Менее популярный, но рабочий метод: хранение в PHP-файле вне document root

Если вы не хотите использовать .env или Composer, можно создать отдельный PHP-файл с конфигурацией и разместить его вне публичной директории.

Структура папок:

/var/www/
├── config/
│   └── database.php  (содержит пароль)
├── public/
│   └── index.php     (точка входа)
└── vendor/

Файл config/database.php:

<?php
return [
    'host' => 'localhost',
    'dbname' => 'myapp',
    'username' => 'myapp_user',
    'password' => 'SuperSecretP@ssw0rd!',
];

В public/index.php:

<?php
$dbConfig = require __DIR__ . '/../config/database.php';

$pdo = new PDO(
    "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']}",
    $dbConfig['username'],
    $dbConfig['password']
);

Плюсы: Простота, не требует Composer, файл недоступен из браузера (если document root — public/).

Минусы: Сложнее управлять разными окружениями (dev/prod), нет стандартизации, файл всё ещё может быть прочитан при локальной атаке на сервер.

Этот подход подходит для очень маленьких проектов или для случаев, когда установка дополнительных библиотек невозможна. Для серьёзных проектов всё же рекомендую .env + phpdotenv.