Настройка Firewall в Mikrotik
RouterOS — сетевая ОС, изначально предназначенная для устройств RouterBoard латвийской компании Mikrotik, но в дальнейшем перекочевавшая на x86 и в облака (версия Cloud Hosted Router). В этой статье поговорим о том, как грамотно настроить межсетевой экран в этой ОС. Безопасность периметра локальной сети — одна из приоритетных задач любого системного администратора и в компании Mikrotik […]
RouterOS — сетевая ОС, изначально предназначенная для устройств RouterBoard латвийской компании Mikrotik, но в дальнейшем перекочевавшая на x86 и в облака (версия Cloud Hosted Router). В этой статье поговорим о том, как грамотно настроить межсетевой экран в этой ОС.
Безопасность периметра локальной сети — одна из приоритетных задач любого системного администратора и в компании Mikrotik это прекрасно понимают. Так что как только вы включили устройство на RouterBoard с настройками по умолчанию — там уже будет некоторое количество преднастроенных правил. В случае Mikrotik CHR — по умолчанию правил не будет, но Mikrotik настоятельно рекомендует их настроить.
Сразу оговоримся, что в рамках этой статьи мы будет пользоваться исключительно интерфейсом командной строки (CLI) и облачной версией RouterOS CHR. Логика настройки точно такая же, как и при использовании WinBox или WebFig, но предпочтительнее изначально пользоваться CLI.
Немного теории: настройка firewall
Одним из базовых понятий настройки файервола Mikrotik является цепочка (chain). По умолчанию их 3, но есть возможность и создания собственных цепочек:
- Цепочка INPUT — входящий трафик, приходящий на маршрутизатор.
- Цепочка OUTPUT — исходящий трафик, создаваемый маршрутизатором.
- Цепочка FORWARD — трафик, проходящий сквозь через маршрутизатор.
Если к нам должен прийти какой-либо трафик извне, например, из интернета, то мы его будем обрабатывать цепочкой INPUT. Чтобы обработать правилами трафик, уходящий наружу (например, в тот же интернет), задействуем цепочку OUTPUT. Если же наш маршрутизатор не находится на границе сети, а служит промежуточным узлом между сетями, то тогда для обработки трафика применяем цепочку FORWARD.
Причем тут странное название «цепочка»? Все элементарно. Все создаваемые правила обработки действуют не вместе, а строго по очереди одно за другим. Точно также, как формируется цепь — одно звено следует за другим. Именно поэтому списки правил стали именовать «цепочками».
Теперь коснемся статусов соединения. Каждое соединение условно можно разделить на 4 категории:
- New — исходя из названия ясно, что это новое соединение, а не одно из существующих.
- Established — соединение установлено, по нему можно передавать пакеты данных.
- Related — соединение, которое относится уже к какому-либо из существующих, но используемое в иных целях. Пока не будем заострять на этом внимание, чтобы не усложнять.
- Invalid — некорректное соединение, то есть маршрутизатор понятия не имеет, что это за соединение и как его обрабатывать.
И сразу к практике: фильтрация
Открываем консольный интерфейс и посмотрим на существующие правила:
[admin@MikroTik] > ip firewall filter print
Flags: X - disabled, I - invalid, D - dynamic
Пока что правил нет, отображается только «легенда» про флаги. Переходим в раздел настройки фильтров:
[admin@MikroTik] > ip firewall filter
[admin@MikroTik] /ip firewall filter>
Полезный чит-код: узнать все варианты команд в любом разделе можно, нажав клавишу со знаком вопроса «?«
Теперь создадим несколько правил и расскажем для чего они нужны:
add action=accept chain=input comment="default configuration" connection-state=established,related
Эту команду можно читать прямо дословно. Разберем прямо по пунктам:
- add action=accept — принимать пакеты.
- chain=input — правило будет работать в цепочке входящего трафика.
- comment=»default configuration» — это просто комментарий-напоминалка, в нашем случае указываем, что это конфигурация по умолчанию, но можно вообще этот параметр не указывать.
- connection-state=established,related — указываем какие статусы соединения будем принимать.
Таким образом эта длинная команда всего лишь превращается во вполне логичную фразу «Принимать извне все пакеты со статусом соединения Established и Related». Это правило позволяет четко указать маршрутизатору что если из внешней сети прилетают соединения с указанными статусами, то их следует принять.
Теперь переходим к следующему правилу, рекомендуемому Mikrotik:
add action=accept chain=input src-address-list=allowed_to_router
Тут мы заострим внимание только на параметре src-address-list=allowed_to_router. При обработке трафика мы можем формировать различные списки IP-адресов. Каждый список будет иметь имя. Так что дословный «перевод» этого правила всего лишь «Принять пакеты, если IP-адрес с которого обращаются, есть в списке allowed_to_router. Нам это правило пригодится для дальнейшего формирования списка разрешенных IP-адресов.
Еще небольшое пояснение. Из-за того, что правила в цепочке обрабатываются одно за другим, то вначале следует прописывать разрешающие правила, а только после этого запрещающие.
Теперь следующее правило, оно достаточно спорное. Мы разрешим маршрутизатору отвечать на команду ping, приходящую извне. С одной стороны — это потенциально раскрывает то, что на нашем IP-адресе есть действующее устройство, а с другой это часто требуется для организации мониторинга. У нас в Selectel, к примеру есть услуга «Мониторинг состояния сервисов», которая позволяет отслеживать доступность любого хоста из разных стран мира. Если вам нужно, отключить ping, то в action надо прописать не accept, а drop.
add action=accept chain=input protocol=icmp
Тут все просто — эта команда разрешает принимать извне и обрабатывать ICMP-пакеты. И завершающая команда:
add action=drop chain=input
Этим в финале цепочки INPUT мы будем отбрасывать (дропать) все оставшиеся пакеты, не подпадающие под правила выше. Посмотрим как у нас сформировались правила:
[admin@MikroTik] /ip firewall filter> print
Flags: X - disabled, I - invalid, D - dynamic
0 ;;; default configuration
chain=input action=accept connection-state=established,related
1 chain=input action=accept src-address-list=allowed_to_router
2 chain=input action=accept protocol=icmp
3 chain=input action=drop
Рассмотрим как же это работает. Представим, что мы пингуем маршрутизатор извне. Это выглядит примерно так:
- Прилетел снаружи ICMP-пакет. Машрутизатор смотрит в правило номер 0 — есть ли уже установившееся соединение. Если нас пингуют впервые, то статус соединение будет New, а не Established или Related. Так что правило не срабатывает.
- Смотрим дальше — есть ли IP-адрес с которого пришел пакет в списке allowed_to_router. Поскольку мы этот список еще не формировали, то его еще не существует и, следовательно, правило также не срабатывает.
- Наконец доходим до правила 2, которое однозначно говорит маршрутизатору, что следует принять (Accept) и обработать по протоколу ICMP данный пакет. Маршрутизатор отвечает на ICMP-пакет соответствующим эхо-ответом. До четвертого правила пакет уже не добирается, т.к. процедура обработки фактически завершена.
Рассмотрим еще один случай. На этот раз к нам на маршрутизатор извне прилетел некий неизвестный UDP-пакет с данными. Как будет действовать маршрутизатор:
- Смотрим правило 0. Существующего Established или Related соединения у нас нет, поэтому правило не срабатывает.
- Правило 1 — смотрим в список разрешенных адресов allowed_to_router, но там пусто. Еще одно правило не сработало.
- Дошли до правила 2 — является ли пришедший пакет ICMP-пакетом. Нет, не является, так что правило не срабатывает.
- И вот мы дошли до конца цепочки INPUT, где нас поджидает «правило-вышибала”. Поскольку у правила chain=input action=drop нет условий для срабатывания, то оно по умолчанию срабатывает всегда и наш неизвестный UDP-пакет дропается и перестает существовать.
Надеемся, что столь подробный разбор логики немного прояснил как именно работает файервол в Mikrotik RouterOS, поэтому приступим к дальнейшей настройке. Сформируем список разрешенных адресов. Для этого вернемся в главное меню, нажав символ / и подтвердив нажатием клавиши Enter. Теперь перейдем в раздел консольного интерфейса Mikrotik – ip firewall и посмотрим какие адресные списки у нас существуют:
[admin@MikroTik] > ip firewall address-list
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
Как видим, список пока пустой. Добавим туда адреса из стандартной локальной подсети 192.168.88.0/24 за исключением 192.168.88.1 (адрес маршрутизатора). Эта подсеть обычно используется по умолчанию на устройствах Mikrotik и именно ее чаще всего используют для раздачи адресов в локальной сети. Выполним добавление:
add address=192.168.88.2-192.168.88.254 list=allowed_to_router
Команда максимально проста для понимания мы говорим, что нам нужно добавить адреса 192.168.88.2-192.168.88.254 в список с именем allowed_to_router. Подразумевается то, что если списка с таким именем не существует, то при выполнении команды он будет создан. Проверим:
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
0 allowed_to_router 192.168.88.2-192.168.88.254 feb/05/2021 13:01:55
Теперь, когда файервол в цепочке INPUT дойдет до правила номер 1, то в случае поступления данных с IP-адресом отправителя из диапазона 192.168.88.2-192.168.88.254 — правило сработает и маршрутизатор будет знать, что данные следует принять. Этим мы будем пользоваться для обращений к маршрутизатору из локальной сети.
Разделяем и властвуем
Списки адресов — крайне полезная штука при настройке файервола. Тут важно следовать стандартам, разработанным такой крутой организацией, как IETF (Internet Engineering Task Force) — Инженерный совет Интернета. Это международное сообщество с конца 80-х годов занимается развитием протоколов и архитектуры интернета.
Результаты работы IEFT публикуются в виде RFC (Request for Comments) — информационных документов, содержащих в себе детальное описание спецификаций и стандартов. Этих документов уже создано несколько тысяч, все они представлены на английском языке. Один из них поможет нам корректно сформировать списки адресов, а именно RFC6890.
Наша задача при настройке файервола четко разделить адреса, относящиеся к локальному сегменту и адреса глобальной сети интернет. Именно их мы возьмем из RFC и пропишем в нашем маршрутизаторе списком с названием not_in_internet. В дальнейшем это поможет нам сформировать правила в которых будут абстракции «это адрес из интернета» и «это адрес не из интернета».
Поочередно выполняем команды, создавая и дополняя список not_in_internet, помимо всего прочего указывая в комментарии номер RFC, которым мы руководствовались:
add address=0.0.0.0/8 comment=RFC6890 list=not_in_internet
add address=172.16.0.0/12 comment=RFC6890 list=not_in_internet
add address=192.168.0.0/16 comment=RFC6890 list=not_in_internet
add address=10.0.0.0/8 comment=RFC6890 list=not_in_internet
add address=169.254.0.0/16 comment=RFC6890 list=not_in_internet
add address=127.0.0.0/8 comment=RFC6890 list=not_in_internet
add address=198.18.0.0/15 comment=RFC6890 list=not_in_internet
add address=192.0.0.0/24 comment=RFC6890 list=not_in_internet
add address=192.0.2.0/24 comment=RFC6890 list=not_in_internet
add address=198.51.100.0/24 comment=RFC6890 list=not_in_internet
add address=203.0.113.0/24 comment=RFC6890 list=not_in_internet
add address=100.64.0.0/10 comment=RFC6890 list=not_in_internet
add address=240.0.0.0/4 comment=RFC6890 list=not_in_internet
Есть еще две важные подсети, которые тоже стоит добавить в этот список. Первая подсеть — это 224.0.0.0/4. Эта подсеть зарезервирована для технологии многоадресного вещания (мультикаст) и это зафиксировано в соответствующем RFC2780. Вторая подсеть специфична для переходного механизма 6to4, позволяющего передавать IPv6 трафик через IPv4 сети. Этот механизм реализован в подсети 192.88.99.0/24, что также зафиксировано в отдельном RFC3068.
add address=224.0.0.0/4 comment=Multicast_RFC2780 list=not_in_internet
add address=192.88.99.0/24 comment="6to4_RFC 3068" list=not_in_internet
Теперь, когда мы все сделали «по фен-шую», у нас есть список всех адресов, которые будут опознаваться как локальные, т.е. пришедшие не из интернета. Проверим:
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
0 allowed_to_router 192.168.88.2-192.168.88.254 feb/05/2021 13:01:55
1 ;;; RFC6890
not_in_internet 0.0.0.0/8 feb/05/2021 13:43:03
2 ;;; RFC6890
not_in_internet 172.16.0.0/12 feb/05/2021 13:43:03
3 ;;; RFC6890
not_in_internet 192.168.0.0/16 feb/05/2021 13:43:03
4 ;;; RFC6890
not_in_internet 10.0.0.0/8 feb/05/2021 13:43:03
5 ;;; RFC6890
not_in_internet 169.254.0.0/16 feb/05/2021 13:43:03
6 ;;; RFC6890
not_in_internet 127.0.0.0/8 feb/05/2021 13:43:03
7 ;;; RFC6890
not_in_internet 198.18.0.0/15 feb/05/2021 13:43:03
8 ;;; RFC6890
not_in_internet 192.0.0.0/24 feb/05/2021 13:43:03
9 ;;; RFC6890
not_in_internet 192.0.2.0/24 feb/05/2021 13:43:03
10 ;;; RFC6890
not_in_internet 198.51.100.0/24 feb/05/2021 13:43:03
11 ;;; RFC6890
not_in_internet 203.0.113.0/24 feb/05/2021 13:43:03
12 ;;; RFC6890
not_in_internet 100.64.0.0/10 feb/05/2021 13:43:03
13 ;;; RFC6890
not_in_internet 240.0.0.0/4 feb/05/2021 13:43:03
14 ;;; Multicast_RFC2780
not_in_internet 224.0.0.0/4 feb/05/2021 13:43:12
15 ;;; 6to4_RFC3068
not_in_internet 192.88.99.0/24 feb/05/2021 13:43:12
Теперь, используя эти листы, создадим еще правила уже в цепочке FORWARD, которые защитят устройства в локальной сети от различных посягательств. Возвращаемся в раздел с правилами:
/ip firewall filter
Первым правилом мы сделаем так, чтобы наш файервол не срабатывал, когда имеет дело с уже установленными соединениями, это лишь тратит ресурсы маршрутизатора и никоим образом не помогает в обеспечении безопасности:
add action=fasttrack-connection chain=forward comment=FastTrack connection-state=established,related
Обрабатываем установленные соединения в цепочке Forward:
add action=accept chain=forward comment="Established, Related" connection-state=established,related
Отбрасываем «битые» соединения:
add action=drop chain=forward comment="Drop invalid" connection-state=invalid log=yes log-prefix=invalid
Отбрасываем пакеты, исходящие из локальной сети к частным IP-адресам и фиксируем срабатывание правила в логах:
add action=drop chain=forward comment="Drop tries to reach not public addresses from LAN" dst-address-list=not_in_internet in-interface=bridge1 log=yes log-prefix=!public_from_LAN out-interface=!bridge1
Отбрасываем входящие пакеты, которые не подходят для NAT и фиксируем срабатывание:
add action=drop chain=forward comment="Drop incoming packets that are not NATted" connection-nat-state=!dstnat connection-state=new in-interface=ether1 log=yes log-prefix=!NAT
Отбрасывать пакеты из сети интернет, пришедшие не с публичных IP-адресов и заносить информацию в лог:
add action=drop chain=forward comment="Drop incoming from internet which is not public IP" in-interface=ether1 log=yes log-prefix=!public src-address-list=not_in_internet
Отбрасывать пакеты из локальной сети, не имеющие IP-адресов этой локальной сети, и также отправляем сообщение в лог:
add action=drop chain=forward comment="Drop packets from LAN that do not have LAN IP" in-interface=bridge1 log=yes log-prefix=LAN_!LAN src-address=!192.168.88.0/24
Защита от атак перебором
Брутфорс-атаки давно стали повседневностью. Десятки тысяч ботов регулярно сканируют весь интернет в поисках открытых портов SSH и затем начинают весьма активно «стучаться» на внешний интерфейс и перебирать пароли в попытке захватить контроль над подключенным устройством. У тех, кто контролирует эти сети есть весьма обширные словари паролей, использующие как дефолтные реквизиты доступа большинства устройств.
Но даже если вы задали сложный пароль — это еще не гарантирует безопасности. Длительная атака перебором способна сломать этот барьер защиты, поэтому проще всего пресекать попытки злоумышленников сразу, как только замечен процесс перебора. Настройка правил firewall у устройств Mikrotik достаточно тривиальна:
Вначале создадим правило firewall по которому все входящие соединения с IP-адресов, находящихся в списке ssh_blacklist будут сбрасываться:
add chain=input protocol=tcp dst-port=22 src-address-list=ssh_blacklist action=drop comment="Drop SSH brutforce" disabled=no
Теперь сформируем сам список ssh_blacklist. Любой имеет право на ошибку, поэтому если легитимный пользователь три раза ошибся во вводе пароля — это нормально. Так что позволим пользователю сделать 3 ошибки с интервалом в 1 минуту. Большее количество будет свидетельствовать о переборе паролей и IP-адрес атакующего будет попадать в черный список и включается блокировка на 10 дней.
Так что нам потребуется создать еще три списка IP-адресов. Первый назовем ssh_stage1. Как только создается новое соединение на порт SSH мы вносим IP-адрес источника в список. При этом задаем удаление через 1 минуту. Это гарантирует нам то, что если соединение прошло успешно — IP-адрес будет удален из списка.
add chain=input protocol=tcp dst-port=22 connection-state=new action=add-src-to-address-list address-list=ssh_stage1 address-list-timeout=1m comment="Stage1" disabled=no
Если даже пользователь ошибся, то ничего страшного, однако если он попробует в течение этой минуты еще раз подключиться, то его адрес мы закидываем во второй список ssh_stage2 из первого списка ssh_stage1.
add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage1 action=add-src-to-address-list address-list=ssh_stage2 address-list-timeout=1m comment="Stage2" disabled=no
Если пользователь ошибется второй раз, то закидываем IP-адрес источника из списка ssh_stage2 в список ssh_stage3.
add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage2 action=add-src-to-address-list address-list=ssh_stage3 address-list-timeout=1m comment="" disabled=no
Третья ошибочная попытка приводит к копированию IP из списка ssh_stage3 в список ssh_blacklist и все входящие соединения с этого IP будут заблокированы сроком на 10 дней.
add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage3 action=add-src-to-address-list address-list=ssh_blacklist address-list-timeout=10d comment="" disabled=no
Для разблокировки адреса будет достаточно его удалить из черного списка.
NAT: базовая настройка и проброс портов
Технология трансляции сетевых адресов (NAT — Network Address Translation) используется во многих случаях. Чаще всего с ней можно встретиться при организации широкополосного доступа к сети интернет. Смысл технологии в том, чтобы дать возможность выходить в сеть множеству устройств, используя всего лишь один внешний IP-адрес.
Все устройства в этом случае будут иметь локальные IP-адреса, например, 192.168.XXX.XXX. Когда устройство запрашивает какой-либо внешний ресурс, то маршрутизатор точно знает от какого адреса в локальной сети пришел запрос и соответственно знает куда направлять обратный поток данных. Но если из внешней сети придет какой-либо запрос, то маршрутизатор его отбросит, поскольку не знает какому устройству в локальной сети его направить.
Решением проблемы является так называемый проброс портов (Port Forwarding). Создавая правило проброса портов мы даем маршрутизатору указания какому устройству перенаправить запрос извне. На логическом уровне подобный запрос может выглядеть как «Если на порт XXX придет TCP-запрос, то перенаправь его на локальный адрес 192.168.XXX.XXX на порт YYY». Давайте посмотрим 2 способа как нам настроить NAT на Mikrotik.
Способ 1. Когда выходной IP-адрес может меняться
Изначально Mikrotik ничего о нашем намерении использовать NAT не знает. Для начала укажем, что хотим все пакеты, пришедшие из локальной сети выводились во внешнюю сеть через общий IP-адрес:
ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade
где ether1 — интерфейс, смотрящий в интернет. Также можно задать не один выходной интерфейс, а сразу несколько, заранее сформировав список out-interface-list.
Этот способ наиболее простой и удобный для пользователей с динамическим IP-адресом.
Способ 2. Когда выходной IP-адрес статический и не меняется
Теперь еще один вариант организации NAT. Рассмотрим пример:
ip firewall nat add chain=srcnat out-interface=ether1 action=src-nat to-addresses=XXX.XXX.XXX.XXX
где XXX.XXX.XXX.XXX — статический IP-адрес, а ether1 — выходной интерфейс.
Теперь переходим к пробросу портов. Для примера предположим, что у нас в локальной сети 192.168.88.0/24 есть небольшой сервер по адресу 192.168.88.10 с поднятым SSH. Нам нужно подключаться к серверу удаленно, используя номер порта 1122. Для этого выполним проброс портов, созданием правила:
ip firewall nat add chain=dstnat in-interface=ether1 protocol=tcp dst-port=1122 action=dst-nat to-addresses=192.168.88.10 to-ports=22
Почему мы взяли такой странный номер порта 1122? Все просто — чтобы затруднить злоумышленникам нахождение номера порта и последующего перебора реквизитов. Таким образом, мы создали правило, однозначно позволяющее маршрутизатору понять, что все TCP-пакеты, пришедшие на порт 1122 следует переадресовывать на локальный адрес 192.168.88.10 на порт 22.
Вместо заключения
Мы рассмотрели основные команды для выстраивания базовой защиты для устройств на базе RouterBoard, а также облачной версии Mikrotik CHR и взглянули на то, как можно парой команд настроить NAT. Разумеется, для каждого неиспользуемого сервиса можно закрыть доступ извне, исходя из используемых портов, протоколов и типа трафика.
Угроз безопасности с каждым днем становится все больше и каждая из них заслуживает внимания и адекватного ответа.