Odoo доступен на наших пяти сайтах из открытого интернета, и это не исключение, а обычная ситуация: кто предлагает услугу, интернет-магазин или вход для клиентов, тот держит публичный сервер. Одного уязвимого пароля, одного забытого файла конфигурации или одного слишком щедрого права доступа достаточно, чтобы публичный сервер стал открытым для всех.
В этой статье показано, как правильно защитить Odoo 19 — не одной мерой, а несколькими слоями, дополняющими друг друга: межсетевой экран и обратный прокси, наш модуль с открытым исходным кодом Web RBL, двухфакторная аутентификация, политика паролей и права доступа — и какие попытки атак каждый из них действительно перехватывает. В конце приведена пошаговая инструкция, по которой можно повторить всё на любой собственной установке Odoo.
Содержание статьи
- Эшелонированная защита: почему одной меры никогда не хватает
- Слой 1: межсетевой экран и обратный прокси
- Слой 2: Web RBL — мост к межсетевому экрану
- Слой 3: защита самого Odoo (2FA, политика паролей, права доступа)
- Слой 4: база данных и эксплуатация
- Путь входа целиком
- Сценарии атак и противодействие им
- Пошаговая инструкция
- Часто задаваемые вопросы
Эшелонированная защита: почему одной меры никогда не хватает
У каждой отдельной меры безопасности есть брешь. Межсетевой экран не видит, что происходит в форме входа Odoo. Надёжный пароль не защищает, если он уже украден в другом месте. Структура прав доступа бесполезна против злоумышленника, который ещё даже не вошёл в систему. Принцип, закрывающий эти бреши, называется эшелонированной защитой (defense in depth): несколько независимых слоёв, каждый из которых по отдельности можно было бы обойти — но все вместе обойти нельзя.
У нас их четыре, и у каждого своя задача:
- Межсетевой экран / обратный прокси — не пускает откровенно вредоносное, ещё до того как оно доберётся до сервера
- Web RBL — соединяет обе стороны: Odoo узнаёт из собственного журнала приложения то, чего межсетевой экран увидеть не может, и передаёт это ему обратно
- Сам Odoo — двухфакторная аутентификация, политика паролей, права доступа, управление сессиями
- База данных & эксплуатация — резервное копирование, защита доступа к управлению, секреты вне любых журналов
В следующих разделах каждый слой разбирается по отдельности.
Слой 1: межсетевой экран и обратный прокси
Межсетевой экран — первая инстанция, которая видит запрос, и единственная, которая способна оградить злоумышленника от любой службы на сервере — не только от сайта, но и от почтового сервера, доступа по VPN и собственного интерфейса управления. Что именно имеет смысл включить здесь, зависит от производителя, но формы реализации у OPNsense, pfSense, HAProxy, FortiGate, Sophos или Check Point одни и те же:
| Функция | От чего защищает |
|---|---|
| Актуальная версия TLS и ограниченный набор методов шифрования | Прослушивание и подмена соединения; устаревшие методы уже много лет считаются взломанными или слабыми |
| Списки репутации и происхождения (RBL) | Известные сети злоумышленников, выходные узлы Tor, целые страны без собственных клиентов — см. ниже |
| Ограничение частоты запросов для каждого адреса | Подбор паролей и сканеры каталогов, отправляющие десятки запросов за секунды |
| Разделение управления и пользовательского трафика | Интерфейс самого межсетевого экрана не должен быть доступен по тому же адресу, что и публичный сайт |
| IDS/IPS (обнаружение/предотвращение атак) | Известные шаблоны атак на сетевом уровне — независимо от того, какое приложение работает за ним |
| Автоматические обновления безопасности для самого межсетевого экрана | Межсетевой экран без исправлений — уже не межсетевой экран, а дополнительная цель |
RBL-списки: стандартный способ доставки репутации
RBL означает Real-time Blackhole List — термин из мира электронной почты: один адрес в строке, доступен по HTTP, регулярно загружается заново. Практически любой межсетевой экран может прочитать такой список и построить на его основе правила — OPNsense и pfSense как URL Table Alias, HAProxy как ACL-файл, FortiGate как External Block List, Palo Alto как External Dynamic List, Cisco, Sophos, Juniper и MikroTik под собственными названиями для одного и того же принципа.
Именно здесь вступает в дело наш собственный модуль — и именно здесь начинается второй слой.
Слой 2: Web RBL — мост между приложением и межсетевым экраном
Межсетевой экран видит пакеты, а не логику приложения. Он не знает, что запрос к /xmlrpc/2/common — это попытка входа, что двадцать разных путей за четырнадцать секунд — это сканер, или что некий адрес только что успешно угадал пароль. Всё это знает только сам Odoo. Web RBL, наш собственный модуль с открытым исходным кодом (AGPL-3), делает это знание пригодным к использованию — для самого Odoo и, будучи выданным в виде RBL-списка, также для стоящего перед ним межсетевого экрана.
Списки угроз постоянно сверяются, у каждого свой уровень.
Кратко о том, что подробно описано в предыдущей статье:
- Распознавание шаблонов в путях: файлы
.env, каталоги.git, файлы конфигурации, зонды WordPress и PHP, обход путей, выполнение команд через новые ИИ-интерфейсы - Защита входа, которая ведёт подсчёт и после перезапусков — в отличие от собственного счётчика Odoo, живущего в оперативной памяти
- Оценка каждого адреса от 0 до 100 с обоснованием простым языком
- Ошибки конфигурации (QNAP, Autodiscover, Synology) распознаются и никогда не блокируются, потому что блокировка не устраняет дефект, а лишь скрывает его
- Сторонние списки угроз, такие как Spamhaus, FireHOL и выходные узлы Tor, постоянно сверяются
- Белый список для адресов, которые никогда не должны блокироваться
Для этой статьи особенно важны два свойства, поскольку они напрямую связаны с межсетевым экраном и со входом в систему.
Инертный список — это список, которому можно доверять
Белый список — адреса, которые никогда не блокируются, например собственные подключения офисов, — как правило, меняется редко. Именно в этом его ценность, а не недостаток: если спокойный список в течение нескольких дней почти не движется, любое редкое изменение сразу бросается в глаза. Ежедневное автоматическое обновление существует не потому, что многое меняется, а для того, чтобы редкое изменение не приходилось вносить вручную, — а именно на этом этапе о нём и забывают. Одна из наших собственных ошибок конфигурации в прошлом месяце была обнаружена именно так: не по множеству событий, а по единственному, о котором никто не знал, пока веб-API QNAP одного клиента не был ошибочно заблокирован. С тех пор QNAP значится в списке ошибок конфигурации, которые никогда не блокируются, а только фиксируются.
Вход — то место, которого межсетевой экран не видит
Межсетевой экран может заблокировать адрес. Но он не может знать, был ли вход успешным, и уж тем более не может знать, пришёл ли он с адреса, который незадолго до этого искал учётные данные. А Web RBL может: оценка, достигшая настраиваемого порога, полностью запрещает вход, а успешный вход с подозрительного адреса фиксируется — это связующее звено со следующим слоем.
Слой 3: защита самого Odoo
Двухфакторная аутентификация: второй секрет, который нельзя использовать повторно
Главная проблема паролей — не их качество, а повторное использование. Пароль, украденный в другой службе, у нас сработает точно так же, пока он совпадает. Двухфакторная аутентификация (2FA, также называемая TOTP) противопоставляет этому второй секрет: шестизначный код, который меняется каждые тридцать секунд и вычисляется из секрета, известного только собственному смартфону. Одного украденного пароля тогда уже недостаточно.
Odoo 19 Community включает это в базовую поставку — в виде устанавливаемого модуля Two-Factor Authentication (TOTP), дополненного резервным вариантом через электронную почту. Каждый пользователь настраивает его для себя сам по QR-коду в любом распространённом приложении-аутентификаторе:
Настройка: отсканировать QR-код, один раз подтвердить шестизначный код — готово.
Но это помогает только тем, кто настраивает его сам, — а опыт показывает, что без принуждения таких остаётся меньшинство. Поэтому в Odoo есть политика обязательного применения: либо только для сотрудников (внутренних пользователей), либо для всех, включая пользователей портала. Без настроенного второго секрета никто больше не пройдёт мимо формы входа, не подтвердив вход хотя бы кодом по электронной почте.
Политика паролей: минимальная длина — не само собой разумеющееся
Без дополнительного модуля Odoo Community не требует никакой минимальной длины пароля — пользователь может задать пароль из трёх символов, если ему никто не помешает. Именно эту брешь закрывает собственный модуль Password Policy: минимальная длина, которая обеспечивается на стороне сервера, а не просто предлагается в браузере. Кто хочет большего — принудительного срока действия, истории против повторного использования, — нуждается для этого в модуле OCA или стороннем; в версии Community это намеренно сведено к минимуму.
Права доступа: доступ получает только тот, кому он нужен
Odoo из коробки разделяет три уровня: пользователи портала (только собственный портал клиента или поставщика), внутренние пользователи (бэкенд с правами по каждому приложению) и администраторы (неограниченный доступ вместе с техническими настройками). Самая частая ошибка — не слишком слабый пароль, а слишком щедро выданная роль администратора: тому, кто должен лишь выставлять счета, не нужен доступ к системным настройкам.
Основную нагрузку несут два принципа:
API-ключ вместо пароля: каждое внешнее подключение (бухгалтерское ПО, учёт времени, собственные скрипты) получает собственный ключ, который можно отозвать в любой момент, но никогда не пароль пользователя.
Оба пункта можно проверить в том же представлении, где настраивается двухфакторная аутентификация:
Один обзор, четыре рычага: пароль, второй фактор, API-ключи, подключённые устройства.
Сессии и устройства: кто сейчас в системе
То же представление показывает также, с каких устройств в данный момент выполнен вход в учётную запись, — и позволяет завершить сеанс на одном из них или сразу на всех. После потери ноутбука или при подозрении на скомпрометированный пароль это самый быстрый действенный шаг: сессия завершается немедленно, независимо от того, был ли уже изменён пароль.
Слой 4: база данных и эксплуатация
Четвёртый слой — наименее заметный и в то же время самый непростительный, потому что ошибка здесь может свести на нет всё построенное ранее.
/web/database/manager интерфейс, с помощью которого можно создавать, сохранять, восстанавливать и удалять базы данных — защищённый лишь одним-единственным главным паролем. Этот интерфейс должен быть доступен исключительно изнутри или полностью отключён.
- Регулярные, проверенные резервные копии, хранящиеся отдельно от самого сервера. Резервная копия, которую никогда не восстанавливали, — это предположение, а не резервная копия.
- Секретам не место ни в одном файле журнала. Пароли, API-ключи, лицензионные данные — кто пишет собственные расширения, должен обращаться с ними так же, как с самим главным паролем: нигде их не записывать, даже «только для отладки».
- Поддерживать модули в актуальном состоянии, в том числе и особенно сторонние. Свободные дополнительные модули (OCA и другие) от природы отстают от новых версий Odoo; перед каждой установкой стоит проверить, какие зависимости подтягиваются автоматически.
Путь входа целиком
Четыре слоя действуют не последовательно в отдельных помещениях, а на одном и том же запросе, ступень за ступенью. Нагляднее всего это видно на примере входа:
Пять мест, где вредоносный запрос может закончить свой путь, не добравшись до настоящей цели, — и только одно, где законный пользователь проходит их все.
Сценарии атак и противодействие им
Следующая таблица сопоставляет реальные шаблоны атак со слоями, которые их действительно останавливают. Многие из них — не теория, а наши собственные наблюдения за семнадцать дней реального трафика на наших пяти сайтах.
| Сценарий атаки | Как он проходит | Что его останавливает |
|---|---|---|
| Подбор паролей | Скрипт пробует сотни комбинаций против формы входа или XML-RPC | Ограничение частоты на межсетевом экране, счётчик Web RBL, сохраняющийся после перезапусков, блокировка после десяти попыток, немедленная блокировка при игнорировании сообщения об ожидании |
| Повторно используемые учётные данные, украденные в другом месте | Злоумышленник уже знает имя пользователя и пароль — из другой, взломанной службы | Двухфакторная аутентификация останавливает вход, несмотря на верный пароль; Web RBL дополнительно сообщает об успешном входе с подозрительного адреса |
| Поиск забытых секретов | Автоматизированные запросы .env, .git, облачных ключей доступа — у нас 57.721 запрос только на .env за семнадцать дней |
Web RBL блокирует при первом же срабатывании; межсетевой экран затем получает адрес в виде записи RBL для всех остальных служб |
| Сканеры каталогов и путей | Десятки выдуманных путей за несколько секунд в поисках забытых приложений | Распознавание поведения: много страниц с ошибками, почти ни одного попадания за короткое время — независимо от того, подпадает ли путь под известный шаблон |
| Неверно настроенное собственное устройство | Клиент синхронизации или почтовая программа по ошибке указывает на неверный адрес и стучится каждую минуту | Распознавание как ошибки конфигурации, а не атаки, заявка вместо блокировки — блокировка не устранила бы дефект, а лишь затянула бы его |
| Автоматизированный сбор обязательных сведений | Сборщик запрашивает страницы Impressum под чужими вариантами написания, зачастую для подготовки волны претензий | Канонический путь остаётся всегда доступным (это юридически необходимо), чужие варианты написания распознаются и фиксируются или блокируются |
| Потерянное или украденное устройство | Ноутбук или мобильный телефон с открытым сеансом попадает в чужие руки | Обзор сессий с немедленным завершением сеансов на всех устройствах, независимо от пароля |
| Слишком широкое внутреннее право доступа | Учётная запись с большими правами, чем необходимо, компрометируется или используется не по назначению | Наименьшие необходимые права для каждого приложения изначально ограничивают ущерб тем, что учётной записи действительно нужно |
| Злоупотребление внешним интерфейсом | Украденный API-ключ или скомпрометированная сторонняя система обращается через XML-RPC/JSON-RPC | Собственные отзываемые API-ключи вместо пароля пользователя; Web RBL отслеживает и неудачные входы через RPC |
| Неверно оценённый краулер поисковой системы | Легитимный краулер создаёт столько трафика, что выглядит как распределённый злоумышленник — на одном из наших сайтов это было более семидесяти процентов всего трафика, создаваемого GPTBot | Белый список с опубликованными диапазонами адресов известных поисковых систем предотвращает ошибочную блокировку, которая исключила бы собственный сайт из индексации |
| Устаревший сторонний модуль с известной уязвимостью | Уязвимость в свободном дополнительном модуле становится публичной, обновление выходит лишь спустя недели | Перед каждой установкой проверять, что подтягивается автоматически; обновления сначала на тестовом экземпляре, а не на живой системе |
| Открытое управление базами данных | Интерфейс управления доступен из открытого интернета; угаданного или слабого главного пароля достаточно, чтобы удалить или скопировать базы данных | Интерфейс никогда не выставляется публично, главный пароль остаётся длинным, случайным и нигде не записанным |
Шаг за шагом: защита собственной установки Odoo
Следующая последовательность — та, в которой мы действовали бы сами, — от наибольшего эффекта до тончайшей настройки.
1. Включить обязательную двухфакторную аутентификацию
- Если ещё не установлено: открыть Приложения, найти «Two-Factor Authentication» и установить (при нескольких сайтах рекомендуется дополнительно «Two-Factor Authentication by Mail» как резервный вариант).
- Открыть Настройки → Общие настройки → Права доступа.
- Включить «Обязательная двухфакторная аутентификация».
- Выбрать политику: «Только сотрудники» для внутренних пользователей, «Все пользователи», если нужно охватить и пользователей портала (клиентов с доступом).
- Сохранить. Начиная со следующей попытки входа Odoo будет требовать от каждого пользователя без настроенного второго секрета как минимум код по электронной почте, пока он не настроит приложение-аутентификатор.
2. Задать минимальную длину паролей
- Открыть Приложения, найти «Password Policy» и установить.
- Открыть Настройки → Общие настройки → Права доступа.
- Задать «Минимальная длина пароля» — двенадцать символов являются разумным начальным значением.
- Сохранить. Правило действует немедленно для каждого нового или изменённого пароля, но не распространяется задним числом на существующие пароли.
3. Просмотреть права доступа
- Открыть Настройки → Пользователи & компании → Пользователи.
- Открыть каждого пользователя по отдельности и проверить вкладку с правами доступа для каждого приложения: действительно ли этому человеку нужен «Менеджер» или «Администратор», или достаточно «Пользователя»?
- Особенно проверить: у кого есть доступ к самим «Настройкам»? Это должна быть очень небольшая группа.
- Для каждого внешнего подключения (бухгалтерия, собственные скрипты, учёт времени) на вкладке «Безопасность учётной записи» соответствующего технического пользователя создать отдельный API-ключ, а не передавать пароль пользователя.
4. Установить Web RBL и наблюдать, прежде чем включать блокировку
- Поместить модуль из github.com/Alex0176/odoo-web-rbl в путь аддонов и установить.
- Несколько дней наблюдать: меню Web RBL → Анализ показывает, какие шаблоны действительно срабатывают.
- Только после этого включить
web_rbl.sperren_aktiv(Настройки → Технические → Системные параметры) — с этого момента распознанные зонды действительно отклоняются. - Подключить список блокировки по адресу, указанному в модуле и защищённому токеном, к межсетевому экрану в качестве RBL-списка (в OPNsense/pfSense как URL Table Alias, в HAProxy как ACL-файл).
5. Защитить сам межсетевой экран
- Сделать интерфейс управления межсетевого экрана доступным исключительно из внутренней сети, а не по тому же публичному адресу, что и сайт.
- Включить автоматические обновления безопасности для программного обеспечения межсетевого экрана, если производитель это предлагает.
- Проверить конфигурацию TLS: только актуальные версии протоколов, устаревшие методы шифрования отключить.
- Если доступно: подключить известный список репутации (например, Spamhaus DROP) прямо на межсетевом экране — независимо от Web RBL, ведь тогда межсетевой экран видит и трафик к службам, до которых Odoo никогда не доходит.
6. Закрыть управление базами данных
- Проверить, доступен ли
/web/database/managerснаружи — если да, задать в конфигурации Odoolist_db = Falseили заблокировать путь на уровне межсетевого экрана. - Задать главный пароль управления базами данных длинным и случайным и не записывать его нигде, где его мог бы прочитать кто-либо ещё.
7. Проверять резервную копию, а не только настраивать её
- Настроить автоматическое регулярное резервное копирование с хранением отдельно от сервера Odoo.
- Хотя бы один раз действительно восстановить её и проверить, работает ли восстановление — непроверенная резервная копия — это предположение.
Ни один из этих шагов не заменяет другой. Кто выполнит только один из них, тот укрепил одну дверь и оставил все остальные открытыми — кто выполнит все семь, тот получит защиту, которая выдержит, даже если откажет один из слоёв.
Чего эта архитектура не заменяет
Ни одна из описанных мер не делает тщательность излишней. Модуль, отклоняющий зонды .env, не делает безопасным случайно опубликованный файл .env. Двухфакторная аутентификация не защищает от пользователя, который зачитывает свой код звонящему по телефону. А межсетевой экран не заменяет решения о том, кому какое право доступа действительно нужно. Архитектура безопасности создаёт условия, при которых отдельная ошибка не сразу превращается в инцидент, — она не снимает ни с кого обязанности быть тщательным.
Часто задаваемые вопросы
Достаточно ли надёжного пароля, чтобы защитить Odoo 19?
Нет. Пароль может быть украден в другом месте независимо от его качества и после этого работает в любой службе, принимающей тот же пароль. Только сочетание с двухфакторной аутентификацией, стоящим перед системой межсетевым экраном и разумной структурой прав доступа даёт защиту, которая выдерживает и кражу пароля.
Как включить двухфакторную аутентификацию в Odoo 19?
Установить модуль «Two-Factor Authentication (TOTP)» через управление приложениями, затем в разделе Настройки → Общие настройки → Права доступа включить обязательное применение и выбрать между «Только сотрудники» и «Все пользователи». После этого каждый пользователь настраивает свой второй фактор по QR-коду.
Что такое RBL-список и зачем он нужен Odoo?
RBL (Real-time Blackhole List) — это список адресов, доступный по HTTP, который может прочитать практически любой межсетевой экран. В самом Odoo такого списка нет — наш модуль Web RBL закрывает этот пробел: он распознаёт атакующий трафик в собственном журнале приложения и возвращает его в виде RBL-списка стоящему перед системой межсетевому экрану.
Достаточно ли защищён Odoo 19 Community без дополнительных модулей?
Не полностью. Без модуля Password Policy нет минимальной длины паролей, без Two-Factor Authentication нет второго фактора, а без такого модуля, как Web RBL, Odoo не распознаёт ни попытки зондирования, ни повторяющиеся попытки входа через перезапуск. Все четыре можно установить дополнительно бесплатно.
Доступность
Web RBL доступен публично под лицензией AGPL-3 и работает у нас в продуктивном режиме на пяти сайтах:
github.com/Alex0176/odoo-web-rbl
Полное описание функций со всеми шаблонами, оценкой и списками угроз приведено в предыдущей статье: Web RBL – список блокировки для атакующего трафика на собственных сайтах.
Вопросы, замечания и сообщения об ошибках мы принимаем с удовольствием — лучше всего в виде issue на GitHub.