MikroTik Настройка Firewall (Update 25.03.2024)

За несколько лет работы, мы для себя нашли некоторую золотую середину в настройке Firewall MikroTik, и естественно хотим поделиться ею с вами.

MikroTik Firewall Filter

Хочу признаться мне не очень нравиться дефолтный конфиг Firewall, но я прекрасно понимаю, что тем кто его придумал, была задача найти условно общую конфигурацию которая бы подходила к большинству и покрывала решение зада большинства, но мы не большинство, и будем “лепить” свой конфиг.

Естественно чистим конфигурацию или просто очищаем полностью Filter Firewall-а.

/ip firewall filter remove [find]

В первую очередь мы должны защитить наш маршрутизатор от условных проблем, атак или злоумышленников из сети интернет.

Interface List ISP

В моём случае для примера у меня три провайдера ether1, ether2, ether3 и поверх ether3 запущен PPPoE туннель для получения доступа к интернету.

Создадим лист интерфейсов в котором перечисляем все интерфейсы подключенные к сетям провайдеров. Причём неважно один или два или десять у вас таковых интерфейсов.

/interface list add name=ISP

Как вы его назовёте, не имеет значения, главное чтобы вам был понятен смысл имени и наверное очень важно, то чтобы было понятно любому другому человеку который взглянет на ваши настройки. Ведь согласитесь если вы его назовёте “Bla-bla-bla” смысл для любого человека будет непонятен, хотя возможно для вас он и будет иметь сакральный смысл.

Я предпочитаю называть данный лист ISP, что обозначает Internet Service Provider.

Соответственно добавляем в данный лист все интерфейсы провайдеров.

/interface list member
add list=ISP interface=ether1
add list=ISP interface=ether2
add list=ISP interface=ether3
add list=ISP interface=ether3.PPPoE

Обратите вниманию я добавил ether3 и PPPoE интерфейс которые поднят через него же. По поводу наименование PPPoE туннеля не удивляйтесь у меня есть привычка использовать в наименовании интерфейсов точку в случае если данные интерфейс является sub интерфейсом другого интерфейса. К примеру если у меня будет vlan 100 на первом интерфейсе его имя будет ether1.100.

На данный момент мы закончили с настройкой листа ISP и может приступить непосредственно к настройке Firewall.

Firewall Filter

Начнём непосредственно настраивать наш filter.

Firewall Filter Input

Первым делом мы будем настраивать трафик, который пришёл на маршрутизатор, и является потенциально опасным для маршрутизатора.

Все дальнейшие правила мы делаем в разделе фильтра, я не буду указывать в приведённых примерах.

/ip firewall filter 

Самым первым правилом отправляем весь трафик с интерфейсов провайдеров в кастомную цепочку (custom chain) с помощью jump.

add chain=input in-interface-list=ISP action=jump jump-target=ISP-Input

С этого момента мы будем работать ТОЛЬКО с цепочкой ISP-Input, про цепочку input можете пока забыть, хотя она нам ещё понадобится.

Следующим правило мы разрешаем, пакеты established которые возвращаются на уже установленное соединение, такие пакеты необходимо разрешать.

add chain=ISP-Input connection-state=established action=accept

Обратите внимание, что я не указываю ни интерфейсы, ни список интерфейсов, нам нет необходимости этого делать, так как самое первое правило отправило в данную цепочку только трафик которые приходит с интерфейсов провайдеров перечисленных в листе ISP.

Следующее правило разрешаем related, это пакеты, которые создали вторичное соединение, такие пакеты помечаются когда на основании какого либо payload создаются новые соединения, например если вы используете NAT-helper ftp или SIP. Также related в некоторых случаях это ICMP ответ маршрутизатора.

add chain=ISP-Input connection-state=related action=accept

Мы часто используем возможность снижение нагрузки на connection-tracker с помощью исключения пакетов с помощью raw untracked, также используется для обхода NAT в случае когда необходимо исключить процедуру изменения заголовка пакета.

add chain=ISP-Input connection-state=untracked action=accept

Кто-то из вас скажет, “Стоп-стоп, но ведь мы можем все эти три последние правила описать одним, просто перечислив состояния через запятую!!! Зачем создавать три правила?!” Да можем, но моя задача, во-первых, показать вам все правила наглядно, а во вторых у нас появляется возможность видеть количество трафика и нагрузку pps по каждому конкретному типу пакетов, и в случае необходимости изменить порядок для оптимизации.

Настала пора создать наше первое запрещающее правило, мы должны запретить пакеты с состоянием invalid, таким состоянием помечаются пакеты в нескольких случаях:

  1. Если на вашем маршрутизаторе закончится память и connection-tracker не сможет создать запись для соединения, но это редкий случай.
  2. Если пакет принадлежит к одному из протоколов GRE, ICMP или TCP, то RouterOS умеет понимать по-содержимому пакетов данные протоколов должен являться данный пакет частью существующего соединения или нет. Если по признакам он является частью соединения, но соединения нет в connection-tracker, то такой пакет помечается как invalid. Пример на маршрутизатор пришёл один пакет TCP с флагами syn и ack, т.е. Какой-то хост “по идеи” ответил на посылку syn пакета, но если соединения нет, то нам такой пакет не нужен. Также это простая защита от TCP RST Flood.
add chain=ISP-Input connection-state=invalid action=drop

Как вы наверное знаете в RouterOS с включенным connection-tracker существует пять состояний пакетов, четыре из которых мы описали, а так как правила в firewall терминирующие, т.е после срабатывания правила пакет прекращает обработку в filter. У нас остаётся всего один тип пакетов это new это те самые пакеты которые создают соединения, другими словами когда кто-то инициализирует соединение к маршрутизатору такой пакет имеет состояние new. Но так как мы описали четыре состояния, нет смысла указывать состояние, так как подразумевается по остаточному принципу, что в следующем правиле и так будут только new.

Мне часто приходится настраивать RouterOS под проекты, и зачастую я подготавливаю оборудование так, чтобы с ним было комфортно работать заказчику, так как со временем у заказчика могут появиться дополнительные кейсы, и чтобы было однотипность в настройках мы поступаем следующим образом.

Выносим все разрешающие правила в отдельную цепочку например с именем ISP-Input-Allow. В таком случае нет необходимости думать в каком месте по порядку разместить правила, чтобы они были правильно расположены относительно всех других правил.

add chain=ISP-Input action=jump jump-target=ISP-Input-Allow

Следующим правилом мы запрещаем все остальные пакеты, которые дошли до следующего правила. Будьте аккуратны, возможно если вы подключены через провайдера к маршрутизатору, вы не сможете подключиться к маршрутизатору в случае разрыва соединения.

add chain=ISP-Input action=drop

Ну вот пожалуй с каркасом закончили, теперь нам необходимо разрешить какой-то трафик на сам маршрутизатор.

Для закрепления результата представим, что у нас поднят на RouterOS l2tp сервер и мы хотим иметь возможность подключаться по ssh, а также маршрутизатор должен отвечать на запросы icmp.

Мы будем использовать кастомную цепочку ISP-Input-Allow и порядок правил в нём не важен, а также неважно расположение правил в этой цепочке относительно всех других правил, хоть в разнобой, хоть в конце, хоть в начале. Это не принципиально. Наверное всё-таки для удобства желательно расположить их по порядку и в одном месте. Но это только для тех кто использует winbox для настроек, а для тех кто используется CLI или как-то оркестратор типа ansible, как раз проявляется удобство в том, что вам не надо думать о прядке правил.

Опишу правила одним блоком

add chain=ISP-Input-Allow protocol=icmp action=accept
add chain=ISP-Input-Allow protocol=tcp dst-port=22 action=accept
add chain=ISP-Input-Allow protocol=udp dst-port=1701 action=accept

Если пакет которых поступает в данную цепочку дойдёт до конца её, то он перейдёт на следующее правило после которого он попал в данную цепочку.

Вот таким образом у вас должен выглядеть filter в winbox.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Я отформатировал вывод убрав отображение некоторых столбцов.

А теперь давайте посмотрим как будут работать данные правила, при поступлении рафика в цепочку INPUT.

Первый пример HOST 5.5.5.5 хочет установить соединение с SSH MikroTik с адресом 2.2.2.2.

Хост 5.5.5.5 отправляет syn пакет для установления соединения с ssh сервером на MikroTik

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Такой пакет первым же правилом попадает под jump и отправляется к custom chain ISP-Input

Далее маршрутизатор находит все правила в кастомной цепочке ISP-Input перебирать соответствию пакета для правила

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

В первых 4 правилах в цепочке ISP-Input он не найдёт соответствия, а вот в пятом правиле сделает jump на ещё одну цепочку. Соответственно выберет все правила из новой цепочке ISP-Input-Allow

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

И будет снова сверять по порядку, соответствия пакета правилу.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Как только найдено терминирующее правило, а в нашем случае это accept, маршрутизатор заканчивает обработку данного пакета в filter firewall и отправляет пакет в Local Process.

SSH сервер ответит пакетом TCP c флагами syn,ack после получения такого пакета клиент отправит пакет с флагом ACK и такой пакет уже будет обрабатываться как established.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall
Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Но первым же правилом в цепочке ISP-input у нас есть разрешающее терминирующее правило для пакетов с состоянием established. Такой пакет сразу отправиться в Local Process.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

А теперь давайте попробуем разобраться, что будет если хост отправит пакет на порт Winbox TCP 8291, который мы явно не запрещали.

Начало будет одинаковое

Васильев Кирилл vasilevkirill mikrotik Filter Firewall
Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Когда пакет будет проверяться соответствиям правилам в цепочке ISP-Input-Allow, для него не найдётся, не одного подходящего правила.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

В этом случае произойдёт автоматически return, и обработка выйдет из цепочки ISP-Input-Allow и продолжит обрабатываться в цепочке ISP-Input а у нас есть правило, которое отбрасывает все пакеты DROP всё, такой пакет не когда, не попадёт в Local Process.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Т.е если в custom chain не найдено соответствие, не с одним правилом, то обработка такого пакета возвращается и продолжает обработку по порядку со следующего правила места входа.

Для удобства восприятия поставил слева номера, чтобы был понятен порядок обработки

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

И ещё раз порядок правил имеет значения только для каждой отдельной цепочки, а не относительно всех цепочек.

Firewall Filter Input Brute-force

В данном разделе мы рассмотрим настройку защиты от перебора паролей по протоколу SSH в сетях с использованием RouterOS.

Изменение порта SSH

Практика показывает, что даже самое простое изменение порта SSH-сервера может сделать вас менее уязвимыми перед большинством сканеров, хотя, конечно, не перед всеми. В локальной сети за маршрутизатором мы можем оставить стандартный порт 22, а с внешней стороны сети изменить его, например, на порт 1024 с использованием простого перенаправления (redirect).

/ip firewall nat
add action=redirect chain=dstnat dst-port=1024 in-interface-list=ISP protocol=tcp to-ports=22
Настройка фильтрации

Далее нам нужно добавить или изменить правило в цепочке ISP-Input-Allow, чтобы разрешить трафик SSH.

add chain=ISP-Input-Allow protocol=tcp dst-port=22 connection-nat-state=dstnat action=jump jump-target=Brute-force 

Обратите внимание на параметр connection-nat-state=dstnat, который позволяет разрешить только тот трафик, который попал под перенаправление dstnat.

Создание цепочки правил Brute-force

Далее создаем кастомную цепочку правил с названием Brute-force, которая будет обрабатывать попытки перебора паролей.

add chain=Brute-force src-address-list=Brute-force-block action=drop 
add chain=Brute-force src-address-list=Brute-force-4 action=add-src-to-address-list address-list=Brute-force-block address-list-timeout=8h
add chain=Brute-force src-address-list=Brute-force-3 action=add-src-to-address-list address-list=Brute-force-4 address-list-timeout=1m
add chain=Brute-force src-address-list=Brute-force-2 action=add-src-to-address-list address-list=Brute-force-3 address-list-timeout=1m
add chain=Brute-force src-address-list=Brute-force-1 action=add-src-to-address-list address-list=Brute-force-2 address-list-timeout=1m
add chain=Brute-force action=add-src-to-address-list address-list=Brute-force-1 address-list-timeout=1m 
add action=accept chain=Brute-force

Эти правила позволяют блокировать адреса, с которых выполняются подозрительные попытки входа, а также ввести тайм-ауты для автоматического разблокирования адресов после определенного времени.

Такая конфигурация поможет усилить безопасность вашего SSH-сервера и снизить риск успешных атак перебора паролей.

На этом этапе мы закончили работу с трафиком Input и переходим к Forward.

Firewall Filter Forward

Естественно нам необходимо защитить трафик, который проходит со стороны провайдеров через маршрутизатор.

Многие наверное скажут, а зачем его защищать, ведь трафик нельзя отправить через маршрутизатор, для этого необходимо адрес маршрутизатора прописать как шлюз, что в свою очередь говорит о том, что маршрутизатор должен находится в Connected сети.

Вот вам маленькая история.

Мне провайдер выдаёт внутренней адрес из сети /22 и со всеми соседями я нахожусь в одном Broadcast домене. Получилось так, что пропустил платёж и мне провайдер на шлюзе зарезал интернет, но он не отключил порт на коммутаторе, и мне всё также была доступна внутренняя сеть. Запустил LLDP на интерфейсе провайдера и увидел что со мной в одной сети находятся как минимум пять маршрутизаторов MikroTik. И логика была у меня такая:

По умолчания в RouterOS на первом порту отключен LLDP, а если я вижу это значит что-либо конфигурации была сброшена либо используется порт не ether1. Соответственно возможно, что на нём неправильно настроен firewall.

Так и получилось я на своём маршрутизаторе прописал адрес MikroTik первого из списка и у меня появился интернет, да с другого IP адреса, но этого достаточно. Сразу скажу, что на всех пяти MikroTik-ах которые я видел, и кстати до сих пор я наблюдаю в сети данные MikroTik c таким образом настроенным Firewall, что я в любой момент могу получить доступ в интернет через них.

Вот именно от таких ситуаций нам необходимо защититься.

И опять же мы будем использовать custom цепочку.

Первым правилом мы отправляем весь проходящий forward трафик с интерфейсов провайдеров в цепочку ISP-Forward.

add action=jump chain=forward in-interface-list=ISP jump-target=ISP-Forward

Следующие правила вам должны быть уже знакомы. Не буду повторять описание

add chain=ISP-Forward connection-state=established action=accept
add chain=ISP-Forward connection-state=related action=accept
add chain=ISP-Forward connection-state=untracked action=accept
add chain=ISP-Forward connection-state=invalid action=drop

Единственно, что необходимо уточнить, это то что в случае если вы используете BGP или асинхронную маршрутизацию. То вам необходимо разрешать трафик invalid. Но в большинстве случаев это не так.

Далее вы помните, что по типу исключения у нас остаётся только пакеты, которые имеют состояние new, и если подумать то такие пакеты могут проходить через маршрутизатор со стороны провайдера только если они попадают под процедуру изменения адреса назначения.

Поэтому нам необходимо разрешить пакеты new которые попадают под dst NAT.

add chain=ISP-Forward connection-nat-state=dstnat action=accept

И последний правилом мы закрываем доступ из вне всем отвальным пакетам.

add chain=ISP-Forward action=drop

Собственно всё.

Давайте взглянем на наши правила.

Васильев Кирилл vasilevkirill mikrotik Filter Firewall

Соответственно, если вам необходимо разрешить подключаться к маршрутизатору, будь то по VPN или ещё как-то, вы всегда можете добавить правило в цепочку ISP-Input-Allow и не думать о порядке правил.

Обновление от 25.03.2024

Как оказалось, множество пользователей, которые используют данный подход при конфигурировании фаервола, да и я сам для себя выработал как стандарт в настройке фаервола.

Иногда не хватает несколько правил, которые мне приходится часто добавлять в конфиг вручную.

ipsec

Мне часто приходится настраивать ipsec, поэтому приходится подтягивать настройки фаервола под него.

Начнем с НАТ-а исключим весь будущий и текущий трафик из обработки NAT-ом, данные правила должны находиться перед всеми правилами изменения заголовка. Эти правила необходимы для того, чтобы трафик, который попадает под ipsec, был исключен из обработки NAT-ом.

/ip firewall nat
add action=accept chain=srcnat ipsec-policy=out,ipsec place-before=0
add action=accept chain=dstnat ipsec-policy=in,ipsec place-before=0

Также я по умолчанию считаю трафик из сетей ipsec доверенным, при этом это не всегда так, но в большинстве случаев.

Нам необходимо добавить несколько правил такого вида в наши цепочки, ПОСЛЕ дропа invalid (Смотри итоговый результат)

/ip firewall filter
add chain=ISP-Input ipsec-policy=in,ipsec action=accept 
add chain=ISP-Forward ipsec-policy=in,ipsec action=accept 

Так как мы иногда можем выступать в роли Responder, нам необходимо открыть соответствующие порты.

/ip firewall filter
add chain=ISP-Input-Allow action=accept dst-port=500 protocol=udp
add chain=ISP-Input-Allow action=accept dst-port=4500 protocol=udp
add chain=ISP-Input-Allow action=accept protocol=ipsec-esp

Brute Force

Я пересмотрел подход с Brute и решил добавить туда же winbox, а это значит, что необходимо переименовать цепочку из SSH-Brute-force в Brute-force и создать правило для winbox.

Так же необходимо уменьшить время нахождения в промежуточных листах, так как 1 минута это очень большой временной промежуток. Сократим его в два раза, до 30 секунд.

Итог (С учетом обновления 25.03.2024)

Я приведу итоговый результат немного отформатированный.

/interface list
add name=ISP

/ip firewall filter
add chain=input in-interface-list=ISP action=jump jump-target=ISP-Input
add chain=forward in-interface-list=ISP action=jump jump-target=ISP-Forward

add chain=ISP-Input connection-state=established action=accept 
add chain=ISP-Input connection-state=related action=accept
add chain=ISP-Input connection-state=untracked action=accept
add chain=ISP-Input connection-state=invalid action=drop
add chain=ISP-Input ipsec-policy=in,ipsec action=accept 
add chain=ISP-Input jump-target=ISP-Input-Allow action=jump
add chain=ISP-Input action=drop

add chain=ISP-Forward connection-state=established action=accept
add chain=ISP-Forward connection-state=related action=accept
add chain=ISP-Forward connection-state=untracked action=accept
add chain=ISP-Forward connection-state=invalid action=drop
add chain=ISP-Forward ipsec-policy=in,ipsec action=accept 
add chain=ISP-Forward connection-nat-state=dstnat action=accept
add chain=ISP-Forward action=drop

add chain=ISP-Input-Allow protocol=icmp action=accept
add chain=ISP-Input-Allow protocol=tcp dst-port=22 connection-nat-state=dstnat action=jump jump-target=Brute-force 
add chain=ISP-Input-Allow protocol=tcp dst-port=8291 action=jump jump-target=Brute-force 
add chain=ISP-Input-Allow dst-port=500 protocol=udp action=accept
add chain=ISP-Input-Allow dst-port=4500 protocol=udp action=accept
add chain=ISP-Input-Allow protocol=ipsec-esp action=accept

add chain=Brute-force src-address-list=Brute-force-block action=drop 
add chain=Brute-force src-address-list=Brute-force-4 action=add-src-to-address-list address-list=Brute-force-block address-list-timeout=8h
add chain=Brute-force src-address-list=Brute-force-3 action=add-src-to-address-list address-list=Brute-force-4 address-list-timeout=30
add chain=Brute-force src-address-list=Brute-force-2 action=add-src-to-address-list address-list=Brute-force-3 address-list-timeout=30
add chain=Brute-force src-address-list=Brute-force-1 action=add-src-to-address-list address-list=Brute-force-2 address-list-timeout=30
add chain=Brute-force action=add-src-to-address-list address-list=Brute-force-1 address-list-timeout=30
add action=accept chain=Brute-force

/ip firewall nat
add action=redirect chain=dstnat dst-port=1024 in-interface-list=ISP protocol=tcp to-ports=22
add action=accept chain=srcnat ipsec-policy=out,ipsec place-before=0
add action=accept chain=dstnat ipsec-policy=in,ipsec place-before=0

На этом на сегодня всё, продолжение следует…

Поделиться

Обсуждение