Безопасность по умолчанию: почему безопасность нельзя добавить одним плагином после запуска
Безопасность — не этап перед релизом. Её нельзя полноценно добавить в последний день проекта одной настройкой, сертификатом или плагином. Если система изначально неправильно работает с пользователями, правами, данными…
Безопасность — не этап перед релизом. Её нельзя полноценно добавить в последний день проекта одной настройкой, сертификатом или плагином. Если система изначально неправильно работает с пользователями, правами, данными и интеграциями, поздние защитные меры закрывают только часть проблем. Хорошая безопасность начинается значительно раньше:
- с архитектуры;
- модели доступа;
- хранения данных;
- способа аутентификации;
- обработки пользовательского ввода;
- настройки инфраструктуры;
- процесса обновлений;
- резервного копирования.
Поэтому правильнее говорить не о «добавлении безопасности», а о security by default — безопасности по умолчанию. То есть система проектируется так, чтобы безопасное поведение было стандартным. Безопасность — это не один инструмент У бизнеса иногда возникает простая модель: Поставим SSL, security-плагин и защитим сайт. HTTPS действительно нужен. Обновления нужны. Security tools тоже могут быть полезны. Но они не заменяют базовую архитектуру. Например, HTTPS не поможет, если обычный пользователь может открыть административный endpoint.
Firewall не исправит неправильную модель ролей. Плагин не решит проблему, если пароли или API-ключи хранятся прямо в репозитории. Поэтому безопасность состоит из нескольких уровней. 1. Authentication: кто вы? Authentication отвечает на вопрос: Кто вы? Когда пользователь входит в систему, приложение должно подтвердить его личность. Например:
- по логину и паролю;
- через SSO;
- через OAuth;
- по одноразовому коду;
- с MFA.
На этом этапе система устанавливает: Это действительно Александр. Но authentication ещё не отвечает на вопрос, что Александр может делать внутри системы. Это уже другая задача. 2. Authorization: что вам разрешено? Authorization отвечает на вопрос: Что вам разрешено? Это принципиально отличается от authentication. Пользователь может быть успешно авторизован в системе, но не иметь права:
- открывать административную панель;
- смотреть чужие заказы;
- менять цены;
- удалять пользователей;
- экспортировать клиентскую базу.
Поэтому хороший контроль доступа строится не по принципу: Пользователь вошёл — значит ему можно. А по принципу: Пользователь вошёл. Теперь проверяем его роль и разрешения для конкретного действия. Простая разница: Authentication — кто вы? Authorization — что вам разрешено? Путаница между этими понятиями часто приводит к серьёзным архитектурным ошибкам. 3. Access control: доступ должен проверяться на каждом уровне Права доступа нельзя реализовывать только через интерфейс. Например, скрыть кнопку «Удалить пользователя» недостаточно.
Если backend всё ещё принимает соответствующий запрос от обычного пользователя, защита существует только визуально. Поэтому access control должен работать на стороне сервера. Проверяется:
- кто делает запрос;
- к какому объекту;
- с каким действием;
- имеет ли пользователь соответствующее разрешение.
Это особенно важно для:
- CRM;
- CMS;
- личных кабинетов;
- медицинских систем;
- финансовых сервисов;
- внутренних корпоративных приложений.
4. Input validation: нельзя доверять входным данным Любые данные, которые приходят извне, нужно проверять. Это касается:
- форм;
- URL;
- API;
- файлов;
- webhook;
- query parameters;
- JSON;
- импортов.
Даже если интерфейс показывает поле «Телефон», backend не должен автоматически предполагать, что туда действительно пришёл телефон. Система должна проверять:
- тип данных;
- длину;
- допустимый формат;
- обязательность;
- диапазон значений.
Validation полезна не только для безопасности. Она делает систему предсказуемее. Чем раньше приложение отклоняет некорректные данные, тем меньше неожиданных ошибок возникает дальше. 5. SQL injection: проблема архитектуры работы с базой SQL injection появляется, когда пользовательский ввод небезопасно попадает в SQL-запрос. На уровне архитектуры защита обычно строится через:
- ORM;
- parameterized queries;
- отказ от небезопасной конкатенации SQL;
- ограниченные права пользователя базы данных.
То есть проблема решается не одной кнопкой в настройках. Она зависит от того, как backend вообще работает с данными. Если запросы строятся правильно изначально, риск значительно ниже. Если нет — поздняя установка дополнительного security-инструмента не исправит весь код автоматически. 6. XSS: пользовательский контент нельзя выводить бездумно XSS связан с тем, как приложение отображает данные в браузере. Например, пользователь вводит текст в форму, а затем этот текст выводится на странице. Если приложение неправильно обрабатывает такой контент, браузер может интерпретировать его не как обычный текст.
Поэтому важны:
- escaping;
- sanitization;
- безопасные шаблонизаторы;
- корректная работа с HTML;
- Content Security Policy там, где она нужна.
Особенно осторожно нужно работать с:
- комментариями;
- rich text;
- пользовательскими профилями;
- CMS;
- HTML-редакторами.
Задача разработчика — заранее определить, где разрешён HTML, а где должен выводиться только безопасный текст. 7. CSRF: действие должно действительно инициироваться пользователем CSRF относится к ситуациям, когда браузер пользователя может отправить действие от его имени без его реального намерения. Особенно актуально это для систем, где пользователь уже авторизован. Поэтому для изменяющих состояние операций используются защитные механизмы:
- CSRF-токены;
- корректные cookie-политики;
- SameSite;
- проверка origin там, где это требуется.
Фреймворки часто предоставляют часть этой защиты автоматически. Но она работает только в том случае, если разработчики не отключают или не обходят её без необходимости. 8. Secrets: ключи не должны жить в коде API keys, пароли, токены и секреты нельзя хранить прямо в исходном коде. Например:
- пароль базы данных;
- секрет приложения;
- ключ платёжной системы;
- API key CRM;
- cloud credentials.
Если они попадают в Git-репозиторий, удалить их позже бывает недостаточно. История уже могла сохраниться. Поэтому secrets должны храниться отдельно:
- environment variables;
- secret manager;
- защищённые конфигурации инфраструктуры.
Также важно разделять секреты между:
- development;
- staging;
- production.
Один и тот же ключ на всех окружениях — лишний риск. 9. HTTPS: базовый уровень, а не вся безопасность HTTPS нужен почти каждому современному сайту. Он защищает передачу данных между браузером и сервером. Особенно это важно, если сайт передаёт:
- формы;
- пароли;
- cookies;
- персональные данные;
- платёжную информацию.
Но HTTPS не делает приложение автоматически безопасным. Он защищает канал передачи. Он не исправляет:
- неправильные права доступа;
- плохую валидацию;
- уязвимые зависимости;
- ошибки backend;
- отсутствие backup.
Поэтому SSL-сертификат — необходимый слой, но не финальная точка. 10. Rate limiting: не каждый запрос нужно принимать бесконечно Некоторые endpoints нельзя оставлять без ограничений. Например:
- login;
- password reset;
- формы;
- публичные API;
- отправка SMS;
- генерация файлов.
Если система принимает неограниченное количество запросов, это может привести к:
- избыточной нагрузке;
- спаму;
- злоупотреблению ресурсами;
- дополнительным расходам.
Rate limiting ограничивает частоту обращений. Например: определённое количество попыток за заданный период. Это не замена authentication или authorization. Это ещё один слой защиты. 11. Dependency updates: код зависит не только от вас Современное приложение почти всегда использует внешние библиотеки. Это:
- framework;
- CMS;
- ORM;
- frontend packages;
- plugins;
- server packages.
Со временем в них находят ошибки и уязвимости. Поэтому поддержка безопасности включает регулярные обновления. Проблема начинается, когда проект несколько лет не обновлялся. Тогда upgrade одной библиотеки может потребовать обновить ещё пять. И обычная техническая работа превращается в большой миграционный проект. Поэтому дешевле поддерживать зависимости постоянно, чем пытаться обновить всё раз в пять лет. 12. Backups: безопасность — это ещё и восстановление Защита системы — это не только попытка предотвратить проблему. Нужно заранее понимать:
Что делать, если проблема всё-таки произошла? Для этого нужны резервные копии. Например:
- базы данных;
- пользовательских файлов;
- конфигурации;
- критических документов.
Но наличие backup ещё не означает, что восстановление работает. Важно проверять:
- как часто создаются копии;
- где они хранятся;
- как долго сохраняются;
- можно ли из них восстановиться;
- сколько занимает восстановление.
Backup, который никогда не тестировали, — скорее надежда, чем процесс. 13. Минимальные права доступа Хорошее правило: Пользователь и сервис должны иметь только те права, которые им действительно нужны. Например, сервису, который только читает данные, не обязательно давать право удалять таблицы. Контент-менеджеру не нужен доступ к инфраструктуре. Обычному пользователю не нужен administrative API. Этот подход называют принципом минимальных привилегий. Он уменьшает возможный ущерб в случае ошибки или компрометации одного компонента.
14. Безопасность должна присутствовать в процессе разработки Даже хорошую архитектуру можно постепенно испортить, если релизы происходят без проверок. Поэтому безопасность должна быть частью delivery process. Например: code → review → tests → dependency checks → staging → production Полезны:
- code review;
- автоматические тесты;
- dependency scanning;
- секрет-сканирование;
- staging;
- логирование;
- мониторинг.
Задача не в том, чтобы превратить каждый сайт в банковскую систему. Уровень защиты должен соответствовать рискам продукта. Безопасность зависит от контекста Не каждому проекту нужен одинаковый уровень защиты. Корпоративный лендинг и банковское приложение имеют разные риски. Но базовые принципы нужны практически везде:
- HTTPS;
- обновления;
- резервные копии;
- безопасная работа с секретами;
- корректная авторизация;
- validation;
- контроль доступа.
Чем чувствительнее данные и критичнее бизнес-процессы, тем глубже должна быть модель безопасности. Что происходит, если безопасность добавлять после разработки Представим, что продукт уже готов. Есть:
- backend;
- CMS;
- личные кабинеты;
- интеграции;
- административная панель.
И только перед релизом появляется задача: Добавить безопасность. Тогда может выясниться:
- роли спроектированы неправильно;
- API не проверяет permissions;
- ключи находятся в коде;
- формы недостаточно валидируются;
- административные функции слишком тесно связаны с публичными;
- audit trail отсутствует.
Исправить всё это можно. Но стоимость изменений будет выше, потому что придётся менять уже готовую архитектуру. Поэтому безопасность дешевле проектировать заранее. Security by default Хорошая архитектура стремится сделать безопасное поведение стандартным. Например:
- пользователь по умолчанию имеет минимум прав;
- критические действия требуют проверки разрешений;
- input по умолчанию валидируется;
- output экранируется;
- secrets не попадают в репозиторий;
- backup создаётся автоматически;
- production работает только через HTTPS;
- зависимости регулярно обновляются.
Разработчику не приходится каждый раз вспоминать: А здесь мы точно не забыли защиту? Большая часть безопасного поведения заложена в платформу. Мини-чеклист безопасности сайта Перед запуском полезно проверить:
- Authentication реализована через надёжный механизм.
- Authorization проверяется на backend.
- Пользователь не получает лишние permissions.
- Все внешние данные валидируются.
- Работа с SQL использует безопасные запросы или ORM.
- Пользовательский контент корректно экранируется.
- CSRF-защита включена там, где она требуется.
- Secrets вынесены из репозитория.
- Production работает через HTTPS.
- Критические endpoints защищены rate limiting.
- Зависимости обновляются.
- Backup создаются автоматически.
- Восстановление из backup проверялось.
- Есть logging и мониторинг.
- Security-проверки входят в процесс релиза.
Главное различие: authentication и authorization Если оставить из статьи только одну мысль, полезно запомнить именно эту. Authentication: Кто вы? Authorization: Что вам разрешено? Система может идеально определять пользователя и при этом оставаться небезопасной, если после входа он получает доступ к чужим данным. Поэтому безопасность не заканчивается на форме логина. Она продолжается в каждом запросе и каждом бизнес-действии. Подход VERB В VERB безопасность рассматривается не как дополнительная опция после завершения разработки.
Она проектируется вместе с продуктом. Мы смотрим на:
- authentication;
- authorization;
- access control;
- input validation;
- secrets;
- dependencies;
- HTTPS;
- backups;
- rate limiting;
- process of deployment.
При этом задача не в том, чтобы усложнить систему максимальным количеством защитных механизмов. Задача — выбрать разумный уровень безопасности под реальные риски бизнеса.
Плагин может усилить безопасность. Но он не может заменить архитектуру.
Если CMS обновляется, но API неправильно проверяет права — проблема остаётся. Если есть HTTPS, но secrets лежат в репозитории — проблема остаётся. Если установлен security-plugin, но никто не проверяет backup — проблема остаётся. Безопасность работает как система слоёв. И чем раньше эти слои предусмотрены, тем дешевле и проще поддерживать продукт дальше.
Хотите понять, насколько безопасно устроен ваш сайт?
VERB может провести технический аудит и проверить:
- authentication;
- authorization;
- permissions;
- input validation;
- зависимости;
- secrets;
- HTTPS;
- резервное копирование;
- rate limiting;
- архитектуру доступа.
На выходе — карта рисков и приоритетов без алармизма: что уже сделано нормально, что стоит исправить сейчас и какие изменения лучше заложить в архитектуру при следующей модернизации. Пришлите сайт на аудит — проверим безопасность как часть продукта, а не как последний плагин перед релизом.