По фреймворкам
Безопасность Ruby on Rails — справочник по продакшн-хардингу
Справочник по продакшн-хардингу Ruby on Rails: приоритетный чек-лист плюс секреты/credentials, конфигурация, CVE gem'ов, Strong Parameters, авторизация, инъекции и SSRF. Защитно, без шагов атаки.
Для: всех, кто ведёт приложение на Ruby on Rails. Здесь нет шагов атаки — это рабочий справочник по хардингу: приоритетный чек-лист, руководство по областям и самопроверка. Полную картину по фреймворкам смотрите на хабе безопасности по фреймворкам.
Приоритетный чек-лист хардинга
Проходите эту таблицу сверху вниз. P0 — предпосылка, P1 — самый частый источник инцидентов, P2 — постоянная эксплуатационная гигиена.
P0 ── Предпосылка (сначала это)
Управление секретами и credentials / продакшн-конфигурация (без раскрытия исключений, force_ssl) / быстрое закрытие CVE gem'ов
P1 ── Главный источник инцидентов
Контроль Strong Parameters/Mass Assignment / авторизация (область владельца)
P2 ── Эксплуатационная гигиена
Инъекции и опасные методы / сессии, CSRF / SSRF, загрузки
| Приоритет | Мера | Конкретика (Rails) |
|---|---|---|
| P0 | Секреты и credentials | Зашифрованные credentials + отдельный master key. Не коммитьте master key. При утечке ротируйте secret_key_base |
| P0 | Продакшн-конфигурация | Не раскрывайте детали исключений; config.force_ssl; filter_parameters, чтобы секреты не попадали в логи |
| P0 | CVE gem'ов (зависимостей) | Мониторьте через bundler-audit / osv-scanner; судите по запущенной версии, быстро закрывайте |
| P1 | Strong Parameters | Держите permit минимальным. Не используйте permit!. Никогда не присваивайте привилегированное поле |
| P1 | Явная авторизация | Pundit / CanCanCan + authorize + область по current_user для владения |
| P2 | Инъекции/опасные методы | Привязывайте в where. Не передавайте ввод в send/constantize. Не загружайте недоверенные YAML/Marshal |
| P2 | Сессии/CSRF | protect_from_forgery (по умолчанию), cookie secure/httponly/samesite, регенерация при входе |
| P2 | SSRF/загрузки | Список разрешённых для серверных запросов + блокировка внутренних IP. Проверяйте загрузки, храните вне public/ |
1. Секреты и credentials (P0)
- Используйте зашифрованные credentials Rails и не коммитьте master (расшифровочный) key в репозиторий (внедряйте через переменные окружения и т. п.).
secret_key_baseлежит в основе подписанных/зашифрованных cookie и сессий. Немедленно ротируйте при утечке (учтите, что это делает недействительными существующие подписи/шифрование).- Не оставляйте
.env, дампы или бэкапы в публичном каталоге (→ не держите секреты в публичных каталогах).
2. Продакшн-конфигурация (P0)
- В продакшене не раскрывайте детали исключений (не включайте
consider_all_requests_localи т. п.) — уменьшайте раскрытие внутренней структуры. config.force_ssl, чтобы принудительно включить HTTPS и пометить cookie как secure. Не включайте инструменты разработки вроде web console в продакшене.- Используйте
filter_parameters, чтобы пароли и подобное не попадали в логи.
3. CVE gem'ов (зависимостей) (P0)
- Машинно мониторьте CVE gem'ов через bundler-audit или osv-scanner, судите по запущенной версии (Gemfile.lock) и быстро закрывайте (→ мониторинг CVE зависимостей · плейбук реагирования на уязвимости).
- Держите Rails и Ruby на поддерживаемых версиях и не оставляйте EOL-версии.
4. Strong Parameters и Mass Assignment (P1)
- Держите поля
permitминимальными и избегайтеpermit!(разрешить всё). - Никогда не присваивайте привилегированное поле вроде
is_adminиз пользовательского ввода. Откажитесь от «разрешу широко, потому что так удобно».
5. Авторизация (P1 — главный источник)
Частое (опасное)
- нет авторизации — «залогинен = можно смотреть/обновлять»
- привязка маршрута к модели достаёт чужой ID
- опора на скрытые маршруты / труднопредсказуемые ID
- забыт
authorizeв некоторых действиях
Правильно
- политика явна через Pundit / CanCanCan +
authorizeна каждое действие - чтения тоже ограничены владельцем по
current_user - проверено на каждом пути чтения/обновления/удаления
- авторизация построена явно, а не оставлена на значения по умолчанию
Смотрите что такое IDOR. Аутентификация и авторизация различны; авторизуйте близко к данным.
6. Инъекции и опасные динамические методы (P2)
- SQL: привязывайте через плейсхолдеры в
where; никогда не стройте запросы конкатенацией строк (избегайтеwhere("... #{params}")) (→ что такое SQL-инъекция). - Опасные динамические методы: не передавайте пользовательский ввод в
send/public_send/constantize. Если необходимо — строго ограничивайте списком разрешённого. - Десериализация: избегайте загрузки недоверенных
YAML/Marshal(при определённых условиях может привести к выполнению кода).
7. Сессии, cookie, CSRF (P2)
- Не отключайте глобально защиту от CSRF (
protect_from_forgery); используйте токен формы (→ что такое CSRF). - Установите secure/httponly/samesite на cookie/сессии и регенерируйте сессию при входе.
8. SSRF, загрузки, заголовки (P2)
- Серверная выборка URL, заданных пользователем, должна ограничивать цели списком разрешённого и блокировать доступ к внутренним IP/метаданным (→ что такое SSRF).
- Проверяйте загрузки (тип/размер), храните вне
public/и не давайте прав на исполнение. - Добавьте заголовки безопасности (проверьте свой сайт через проверку заголовков безопасности).
Проверьте: действительно ли ваш Rails укреплён?
Собрать — ещё не конец: работа сделана только после проверки. Это защитные самопроверки против собственной среды.
Секреты не раскрыты/не закоммичены
master.key нет в репозитории и что .env/дампы не забираются по URL.Нет деталей исключений в продакшене
Авторизация держится
Зависимости и заголовки
bundler-audit/osv чист и что HTTPS/HSTS присутствуют — через проверку заголовков.Взгляд нашего сайта: даже под защитой соглашений авторизация и зависимости на вас
Хорошие значения по умолчанию Rails снимают много риска, но авторизация — кто что может делать — и свежесть зависимостей специфичны для приложения и эксплуатации, поэтому фреймворк не может защитить их автоматически. Инциденты, которые мы видим снова и снова, — не изощрённые атаки, а тип «аутентифицирован, но нет проверки владения». Поэтому центр тяжести — проходить таблицу выше сверху вниз: затяните Strong Parameters, сделайте авторизацию явной и мониторьте gem'ы на CVE.
Читать дальше
- Хаб: безопасность по фреймворкам · безопасность Laravel (тот же MVC, похожая форма авторизации)
- Практика: плейбук реагирования на уязвимости · мониторинг CVE зависимостей · не держите секреты в публичных каталогах
- Глоссарий: что такое IDOR · SQL-инъекция · CSRF · SSRF
- Инструменты: проверка заголовков безопасности
FAQ
QЧто сделать в первую очередь для защиты Rails?
Три пункта P0: (1) безопасно обращайтесь с секретами (держите зашифрованные credentials отдельно от master key, не коммитьте master key; secret_key_base лежит в основе подписанных/зашифрованных cookie, поэтому при утечке — ротация); (2) укрепите продакшн-конфигурацию (не раскрывайте детали исключений; force_ssl); (3) машинно мониторьте CVE gem'ов (зависимостей) и быстро закрывайте, судя по запущенной версии. Дальше переходите к Strong Parameters и авторизации.
QНа что обращать внимание со Strong Parameters?
Явно разрешайте (permit), какие поля вы принимаете, чтобы предотвратить Mass Assignment (массовое присвоение непреднамеренных полей). Опасность — разрешать широко ради удобства и использовать permit! для разрешения всего. Держите разрешённые поля минимальными и никогда не позволяйте присваивать привилегированное поле вроде is_admin из пользовательского ввода.
QКак безопасно реализовать авторизацию?
Поверх входа (аутентификации) реализуйте проверку владения — что цель действительно принадлежит пользователю. Сделайте политику явной через Pundit/CanCanCan, вызывайте authorize в каждом действии и ограничивайте ресурсы областью current_user. Не полагайтесь на скрытые маршруты или труднопредсказуемые ID — проверяйте явно на каждом пути чтения/обновления/удаления.
QКак управлять уязвимостями gem'ов (зависимостей)?
Машинно мониторьте известные CVE через bundler-audit или osv-scanner и быстро закрывайте, судя по запущенной версии (решайте по фактической версии в Gemfile.lock). Держите Rails и Ruby на поддерживаемых версиях и не оставляйте EOL-версии. Свежесть зависимостей — более реалистичный фактор инцидентов, чем изощрённые атаки.
QКакие динамические методы опасны?
Передача пользовательского ввода в send / public_send / constantize может привести к непреднамеренному вызову метода или разрешению класса. Аналогично, загрузка через Marshal или недоверенный YAML (восстановление объектов) при определённых условиях может привести к выполнению кода. Не передавайте им данные пользовательского происхождения; если необходимо — строго ограничивайте списком разрешённого.