MAATRIX / Блог / Ежеквартальная проверка прав на файлы: где 777 пережил три года

Ежеквартальная проверка прав на файлы: где 777 пережил три года

MAATRIX

Ночь, дедлайн, приложение падает с Permission denied, и вместо того чтобы разбираться, кому конкретно нужен доступ, кто-то в отчаянии делает chmod -R 777 /var/www/uploads. Ошибка пропадает, релиз выкатывается, инцидент закрыт — а команда chmod 750 обратно так и не выполняется, потому что на неё уже никто не переключился. Пройдёт квартал, потом год, потом три — и эта директория с правами 777 просто будет лежать на проде, пока её случайно не найдёт аудитор, пентестер или, что хуже, злоумышленник. Ниже — практический разбор: как искать такие места на реальном сервере, чем плохи чрезмерно открытые права на практике, и как их закрывать, не сломав работающее приложение.

Почему 777 не лечится сам собой

Проблема не в конкретном инженере, который поставил 777 в три часа ночи — это рациональное поведение в моменте. Открыть права максимально широко — самый быстрый способ исключить права доступа как причину ошибки и двигаться дальше. Проблема в том, что у этого действия нет естественного триггера для отмены.

Сравните с другими временными мерами. Отключили firewall для теста — это видно в мониторинге. Подняли тестовый стенд с боевыми доступами — рано или поздно кто-то спросит, зачем стенд ходит в прод. А права 777 физически не мешают ничему работать правильно — только создают возможность работать неправильно. Сайт как работал, так и работает, ошибок в логах нет, Sentry молчит. Единственный способ узнать о проблеме — специально её искать.

Три года — не преувеличение, а типичный срок жизни такой находки в проде на реальных ревизиях. За это время:

  • сменился инженер, который ставил 777, и знание о временности решения ушло вместе с ним;
  • директорию несколько раз бэкапили и разворачивали заново — права скопировались как есть;
  • сервер один-два раза мигрировал на новое железо через rsync -a или tar, который добросовестно сохранил все атрибуты, включая ошибочные;
  • в директории появились новые файлы и поддиректории, которые унаследовали открытые права через umask или явное копирование прав родителя.

К моменту находки открытых прав уже не одна директория, а целое дерево, и понять, кто и зачем это сделал, почти невозможно — Git не хранит историю файловой системы, а chmod не пишется в журнал по умолчанию. Похожая динамика возникает и при массовом копировании данных между серверами, когда права молча переносятся вместе с файлами и никто их потом не пересматривает. Подробнее о механике вреда конкретно от 777 — в статье почему совет chmod 777 ломает сервер.

В чём конкретно риск, если 777 никто не эксплуатирует

Аргумент «ну и что, всё равно работает, никто не ломал» звучит убедительно ровно до первого инцидента. У избыточных прав есть три конкретных сценария вреда, а не абстрактная «небезопасность».

Эскалация через соседний процесс. На сервере редко живёт одно приложение: сайт на PHP-FPM, воркер на Node, cron-скрипт на Python — каждый может быть скомпрометирован независимо через уязвимую зависимость или инъекцию в форму загрузки. Директория с правами 777 — готовый плацдарм: скомпрометированный процесс с правами www-data может записать веб-шелл или подменить конфиг в директории, которая по логике вообще не должна быть доступна на запись извне.

Запись файла с чужим исполняемым содержимым. Классика — загрузка «картинки», которая на самом деле PHP-скрипт с двойным расширением или подменённым MIME-типом. Если директория загрузок имеет 777 и одновременно исполняется веб-сервером, связка «открытая запись + возможность исполнения» превращает баг загрузки файлов в полноценный RCE.

Провал внешнего аудита или комплаенса. Даже без технической эксплуатации найденные при пентесте или SOC 2 / ISO 27001 аудите открытые права — готовый пункт в отчёте, который придётся объяснять клиенту или регулятору. Дешевле найти и закрыть это самому за час, чем получить строкой в чужом отчёте с дедлайном на исправление.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Как искать: команды для поиска открытых прав

Базовый инструмент — find с флагом -perm. Он одинаково доступен в Debian, Ubuntu, AlmaLinux и большинстве других дистрибутивов без установки дополнительных пакетов.

Файлы, доступные на запись кому угодно (world-writable):

find / -xdev -type f -perm -0002 -not -type l 2>/dev/null

Директории, доступные на запись кому угодно, но без sticky bit (то есть любой пользователь может не только писать файлы внутрь, но и удалять чужие файлы — как в /tmp без защиты):

find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/null

Флаг -xdev держит поиск в пределах одной файловой системы и не уходит в /proc, /sys и сетевые шары, где такие находки — норма. При нескольких разделах (например, отдельный том под /data) запускайте поиск на каждом отдельно, указав путь вместо /.

Прямой поиск ровно 777 (жёстче, чем «world-writable» — ловит только максимально открытые права, без учёта прав группы и владельца):

find /var/www -type f -perm 0777 -o -type d -perm 0777

Обратите внимание: -perm -0002 и -perm 0777 — разные проверки. Минус перед маской означает «хотя бы эти биты установлены» (найдёт и 777, и 767, и 646), а маска без минуса означает «права установлены ровно так» (найдёт только точное совпадение). Для ежеквартального аудита обычно нужен первый вариант — он ловит больше реальных проблем.

Файлы, доступные на запись группе, если группа — не та, что нужна:

find /var/www -type f -perm -0020 2>/dev/null -exec stat -c '%a %U:%G %n' {} \;

stat сразу выводит режим доступа и владельца — удобнее, чем смотреть на голый список путей.

Ещё один полезный поиск — файлы без владельца или без группы (обычно остаются после удаления пользователя и по факту доступны всем, у кого совпадёт освободившийся UID):

find / -xdev \( -nouser -o -nogroup \) 2>/dev/null

Для точечной проверки одного пути и понимания, откуда взялись эффективные права (включая права родительских директорий), удобна команда namei:

namei -l /var/www/uploads/avatars

Она построчно покажет права каждого сегмента пути — иногда выясняется, что сама директория avatars настроена правильно, а проблема в 777 на одном из родителей выше по дереву.

SUID, SGID и особые биты — отдельная категория

Помимо обычных чрезмерно открытых прав на чтение/запись отдельно стоит искать файлы с битами SUID и SGID — они позволяют запускать программу с правами владельца файла (обычно root), а не запустившего пользователя. Легитимных SUID-бинарников на сервере обычно немного — passwd, sudo, su, mount и десяток похожих системных утилит.

find / -xdev -perm -4000 -type f 2>/dev/null   # SUID
find / -xdev -perm -2000 -type f 2>/dev/null   # SGID

Практика: сохраните вывод этих двух команд сразу после чистой установки сервера в текстовый файл — это будет ваш baseline. При каждой квартальной проверке сравнивайте текущий список с baseline через diff. Любая новая строка — повод разобраться, кто и зачем поставил SUID-бит на нестандартный бинарник (частый источник — забытый после отладки chmod u+s на скрипт, «который иногда не может писать в лог», или, в худшем случае, след компрометации). Более подробный разбор — в статье SUID-файл, которого не должно быть: как проверить.

Отдельно стоит помнить про ACL — расширенный слой прав поверх обычных unix-битов, который ls -l не показывает (только символ + в конце строки намекает на его наличие):

getfacl /var/www/uploads

Если на директории когда-то настраивали ACL для конкретного пользователя (setfacl -m u:deploy:rwx /var/www), обычный аудит по find -perm эту настройку не увидит — права на уровне владельца/группы/остальных выглядят нормально, а реальный доступ шире. Если ACL используются в инфраструктуре, включайте getfacl -R по ключевым директориям в тот же квартальный чек-лист.

Прежде чем ужесточать: поймите, почему права именно такие

Самая частая ошибка после находки — сразу выполнить chmod -R 750 и уйти довольным. Такое исправление ломает работающее приложение почти так же часто, как исходная проблема с 777 создавала риск, просто в другую сторону: вместо тихой уязвимости вы получаете громкий Permission denied в проде.

Перед тем как менять права, ответьте на три вопроса по каждой находке.

Кто реально пишет в эту директорию? Посмотрите, какой пользователь запускает процесс, работающий с этим путём:

ps -eo user,cmd | grep -i nginx
ls -la /var/www/uploads | head -1     # текущий владелец директории

Если веб-сервер работает от www-data, а директория принадлежит root:root с правами 777 — вероятно, кто-то в момент отладки не стал разбираться с chown, а просто открыл права всем. Правильное исправление — не 750 на текущем владельце, а смена владельца на www-data (или нужную группу) с одновременным ужесточением прав.

Действительно ли запись сюда нужна извне процесса приложения? Директория логов, кэша или временных файлов, которую пишет только сам процесс, не должна быть доступна на запись группе или остальным вообще — 750 или даже 700. А директория, куда одновременно пишут веб-сервер и, например, деплой-скрипт от другого пользователя — повод для отдельной группы с правами 770, а не для общих 777 на всех.

Есть ли активность прямо сейчас, которую вы прервёте? Перед изменением прав на боевой директории проверьте, что в неё не идёт запись и нет открытых файловых дескрипторов от процессов, которым доступ должен остаться:

lsof +D /var/www/uploads 2>/dev/null

Если список непустой — сначала разберитесь, что это за процессы, и только потом меняйте права; лучше сделать это в окно с минимальной нагрузкой, а не в пик трафика.

Процесс безопасного исправления

Когда причина понятна, действуйте по шагам, а не одной командой на весь поддерево.

  1. Зафиксируйте текущее состояние. Прежде чем что-то менять, сохраните снимок прав — на случай если исправление всё-таки что-то сломает и нужно быстро откатиться:
find /var/www/uploads -printf '%m %u:%g %p\n' > /root/perm-audit/uploads-before-$(date +%F).txt
  1. Меняйте владельца и права раздельно и явно, а не полагайтесь на рекурсивный chmod с общей маской:
chown -R www-data:www-data /var/www/uploads
find /var/www/uploads -type d -exec chmod 750 {} \;
find /var/www/uploads -type f -exec chmod 640 {} \;

Раздельные права для файлов (640) и директорий (750) — не опечатка: у директории бит выполнения означает право заходить внутрь и листать содержимое, файлам данных x почти никогда не нужен.

  1. Проверьте на staging или в окне с низкой нагрузкой, а не сразу на 100% прода. Если staging нет, применяйте изменения сначала к одной поддиректории и понаблюдайте 10-15 минут за логами.
  1. Мониторьте логи ошибок сразу после изменения — конкретно на Permission denied и похожие сообщения:
tail -f /var/log/nginx/error.log /var/log/app/error.log | grep -i "permission denied"
  1. Задокументируйте находку и решение — хотя бы одной строкой в журнале изменений сервера: что нашли, что сделали, почему. Это тот самый контекст, которого не хватило через три года в примере из начала статьи.

Если после исправления что-то ломается — это неплохой знак: значит, вы нашли не забытый мусор, а актуальную (пусть и криво реализованную) зависимость приложения от широких прав, и теперь можно решить её правильно — явным chown или ACL-записью, а не откатом обратно на 777.

Как встроить проверку в регулярный цикл, а не делать раз и забыть

Одноразовый аудит закрывает то, что накопилось к текущему моменту, но не защищает от следующего инцидента с временным chmod 777 через полгода. Смысл именно квартальной проверки в том, что интервал достаточно короткий, чтобы находки были свежими и объяснимыми (человек, который менял права, скорее всего ещё работает и помнит контекст), и достаточно редкий, чтобы не превращаться в шум.

Практическая схема:

  • Заведите скрипт, который прогоняет команды поиска выше и складывает результат в датированный файл: /root/perm-audit/scan-2026-08.txt.
  • Сравнивайте новый скан с предыдущим через diff — так вы увидите не весь список (он может быть длинным и легитимным), а именно новые находки за квартал.
  • Заведите отдельный baseline-файл для SUID/SGID бинарников — по нему изменения должны случаться почти никогда, любая новая строка требует объяснения в тот же день.
  • Включите шаг проверки прав в существующий квартальный ритуал, если он уже есть — например, туда же, где идёт ревизия доступов пользователей: темы разные (кто может зайти vs что можно сделать внутри), но естественно проверяются в одну сессию.
  • Если квартальный цикл кажется слишком редким для вашего профиля риска — добавьте облегчённую версию проверки в еженедельный регламент обслуживания: нескольких минут на прогон find по ключевым директориям хватит.

Для системного аудита, смотрящего на права шире отдельных файлов (конфигурация SSH, firewall, пакеты), можно опираться на готовые инструменты вроде Lynis — они тоже подсвечивают избыточные права. Но они не заменяют точечный find-аудит директорий приложения: инструмент не знает вашей бизнес-логики и не отличит «эта директория специально общая для группы деплоя» от «это забытая дыра».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли просто запустить chmod -R 750 на весь сервер и не разбираться по одной директории?

Нет — это почти гарантированно сломает что-то работающее: системные бинарники с SUID-битом, сокеты с особыми правами, директории с намеренно широким доступом для группы деплоя. Массовое исправление без разбора причины меняет один тип риска на другой.

Как понять, что находка — забытый 777, а не намеренная конфигурация?

Смотрите на контекст: если директория содержит файлы одного приложения и права шире, чем нужно ему для работы — почти наверняка забытая мера. Если права широкие осознанно (общая директория для нескольких сервисов от разных пользователей), это обычно видно по составу файлов и активности нескольких разных владельцев.

Что делать, если находок оказалось очень много — десятки директорий?

Не закрывайте всё за один вечер. Сортируйте по критичности: сначала document root веб-сервера (риск RCE выше всего), затем конфиги и секреты, затем остальное — по несколько находок в неделю, с задокументированным планом.

Нужно ли делать эту проверку на новом сервере?

Да, но пользы сразу после установки будет мало — ценность растёт со временем по мере накопления временных решений. Тем не менее стоит сразу снять baseline (список SUID-файлов и первый скан) — сравнивать потом будет не с чем.

Отличается ли подход для контейнеров (Docker)?

Принципиально нет — find с теми же флагами работает и внутри контейнера, и на хосте. Разница в том, что образ пересобирается при каждом деплое, поэтому забытый 777 в Dockerfile воспроизводится при каждом обновлении — это и хуже (масштабируется на все инстансы), и лучше (легче найти, проверив сам Dockerfile).

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →