Руководства по безопасности
Как держать .env вне публичного веба на общем хостинге
Сделайте .env, .git и vendor недостижимыми, когда вы развёртываете приложения в стиле Laravel на общем хостинге. Настоящее исправление: тело приложения вне веб-корня, наружу только public/. Диаграмма размещения, первая помощь через .htaccess, реструктуризация, ловушка bootstrap-redirect этого сайта и самопроверка.
Для всех, кто запускает приложения в стиле Laravel (где наружу должна быть только public/) на общем хостинге с Apache/.htaccess. Выжато из реального инцидента (→ .env выставлен всему миру) — для защиты своего собственного развёртывания.
Взгляд этого сайта: это не «ошибка одного человека»
Ранняя культура общего хостинга клала всё прямо под public_html. Laravel (который ожидает наружу только public/) влился в это, и опасная раскладка стала де-факто стандартом — даже собственные документы вендоров кладут проекты внутрь public_html. Поэтому исправление — это процесс, а не бдительность: измените значение по умолчанию для развёртывания.
Сделайте размещение правильным (диаграмма)
✗ Опасно (тело в публичном корне)
public_html/ ├─ .env ← читаемо! ├─ .git/ vendor/ └─ public/
✓ Безопасно (тело снаружи, только public)
app-laravel/ ← вне веб-корня ├─ .env .git/ ← недостижимо └─ public/ → подключается из public_html
Шаг 1: Первая помощь (быстро, обратимо)
Добавьте блок deny в начало .htaccess веб-корня (пример защитной конфигурации). Обычные страницы не затронуты.
# === SECURITY BLOCK ===
RedirectMatch 404 (?i)/\.(env|git)(\..*)?(/|$)
<FilesMatch "(?i)\.(sql|sql\.gz|bak|old|swp|save|orig|tgz)$|^credentials\.json$|\.bk[._]">
Require all denied
</FilesMatch>
<FilesMatch "(?i)^(phpinfo|info)\.php$">
Require all denied
</FilesMatch>
# if Laravel internals are visible at /<app>/storage/... etc.
RedirectMatch 403 (?i)^/[^/]+/(storage|bootstrap/cache|config|database|resources|routes|tests|vendor)(/|$)
# === END ===Первая помощь — не цель
Чёрный список — это игра в «убей крота» — вы забудете composer.lock, новые имена файлов добавят новые дыры. Считайте его выигрышем времени до Шага 2.
Шаг 2: Реструктуризация (постоянное исправление)
Переместите тело приложения вне веб-корня и оставьте крошечную точку входа, которая просто загружает его.
# 1. Move the body outside the web root (same filesystem → mv is instant, atomic)
mv ~/example/public_html/app ~/example/app-laravel
# 2. Put only a minimal entry in the web root
mkdir -p ~/example/public_html/sub
cat > ~/example/public_html/sub/index.php <<'PHP'
<?php require __DIR__ . '/../../app-laravel/public/index.php';
PHP
# 3. Copy Laravel public/.htaccess, symlink static assets
# 4. Clear config cache
rm -f ~/example/app-laravel/bootstrap/cache/{config,services,packages,routes-v7}.phpВыстраданная ловушка этого сайта: bootstrap-redirect лучше симлинка
Сделать сам public_html симлинком на public/ может вернуть 500 на docroot зарегистрированного поддомена в некоторых средах (он не срабатывает). Держать docroot реальной директорией и подключать (require) по абсолютному пути из маленького index.php (форма «bootstrap-redirect») стабильнее на общем хостинге с ограниченной областью. Также opcache может запомнить неудачную загрузку и продолжать возвращать 500 — крайнее средство это сменить имя файла точки входа (entry.php).
Шаг 3: Ротируйте ключи (считайте, что их видели)
Если было любое окно выставленности, считайте ключи .env уже увиденными и замените их. Порядок: внешние API / OAuth-секреты → ключи шифрования → почта → БД. См. глоссарий .env. Переиздание OAuth-секрета может аннулировать refresh_token-ы, поэтому сначала подготовьте поток повторной авторизации.
Шаг 4: Самопроверка (сделайте привычкой)
Наконец, убедитесь, что ничто действительно не выставлено на вашем собственном сайте (только против доменов, которыми вы владеете).
# A 200 with a body means it's exposed. 403/404 is okay for now.
curl -sI https://your-domain/.env | head -1
curl -sI https://your-domain/.git/config | head -1Проверка этого при каждом развёртывании рано ловит ошибки размещения.
Читать дальше
- Инцидент: .env, выставленный всему миру
- Глоссарий: что такое .env
- Основы: чем опасны .env и API-ключи
FAQ
QЧто самое быстрое, что я могу сделать прямо сейчас?
Добавьте блок deny в .htaccess вашего веб-корня для .env, .git, SQL-дампов, credentials.json и т. д. Это обратимо и не влияет на обычные страницы — но это первая помощь; настоящее исправление — реструктуризация.
QПочему одного .htaccess недостаточно?
Чёрный список — это игра в «убей крота»: новые имена файлов добавляют новые дыры. Переместите тело приложения вне веб-корня — и до .env просто не добраться, без правил для поддержки.
QПочему не просто симлинкнуть public/, чтобы выставить его?
В некоторых средах перенаправление docroot зарегистрированного поддомена на другое дерево через симлинк не срабатывает и возвращает 500. По опыту этого сайта, держать docroot реальной директорией и подключать (`require`) по абсолютному пути из маленького index.php (форма «bootstrap-redirect») стабильнее.