Для дополнительной защиты сервера от злоумышленником, помимо файрвола, используется метод «простукивания портов». Принцип работы port knocking сводится к обращению в определенном порядке и за определенный период времени к цепочке заранее указаных портов. Если последовательность обращения верная и она была произведена в заданный промежуток времени то выполняется команда, к примеру правило файрвола, и открывается нужный порт, после чего вы можете к нему подключиться.
Port knocking можно использовать не только для предоставления доступа к конкретному порту, но также запускать любые команды либо скрипты, к примеру, таким образом вы можете запускать резервное копирование, запускать рассылку сообщений либо отправлять разнообразные уведомления.
Принцип работы
Для настройки на стороне сервера мы будем использовать утилиту knockd. Утилита knocd работает в режиме демона и совместно с iptables прослушивает сетевой трафик ожидая корректной последовательности запросов на подключение.
В тот момент когда knockd получается верную последовательность, которая указана в конфигурации knockd, выполняется правило iptables которое разрешает подключение на определенный сетевой порт, либо можно выполнить любую произвольную команду или даже скрипт.
Установка и настройка knockd
Утилита knockd доступна во всех современных дистрибудивах linux и установить вы можете ее одной командой
apt install knockd
Если же по каким-то причинам данная утилита недоступна в вашей системе вы можете скачать исходники которые доступны на официальном сайте и скомпилировать ее.
После установки установим автоматический запуск knockd, для этого откроем файл который находится по адресу /etc/default/knockd
nano /etc/default/knockd
Для автоматического запуска демона knockd необходимо изменить значение START_KNOCKD и установить его равным 1.
START_KNOCKD=1
Перейдем к настройке knock, файл конфиуграционный файл находится по адресу /etc/knockd.conf, откроем его и отредактируем.
nano /etc/knockd.conf
В секцию [options] нам необходимо добавить интерфейс который утилита knockd будет прослушивать. Чтобы узнать имя вашего интерфейса, выполните команду ifconfig, у меня один интерфейс с именем enp0s3.
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.98 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::a00:27ff:fede:11e0 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:de:11:e0 txqueuelen 1000 (Ethernet)
RX packets 40043 bytes 45766404 (45.7 MB)
RX errors 0 dropped 961 overruns 0 frame 0
TX packets 3949 bytes 706255 (706.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Приводим секцию [options] к следующему виду
[options]
UseSyslog
Interface = enp0s3
В стандартной конфигурации в качестве примера указаны две последовательности [openSSH] и [closeSSH] их мы с вами разберем подробнее.
[openSSH]
sequence = 7000,8000,9000
seq_timeout= 5
command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 9000,8000,7000
seq_timeout= 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
Последовательность [openSSH] у нас отвечает за «открытие» 22 порта, а последовательность [closeSSH] за его «закрытие» . Для того чтобы порт 22 был доступен необходим сделать запрос на порт 7000, 8000, 9000 , а для того чтобы закрыть доступ к порту 22 необходимо выполнить обратную последовательность на 9000, 8000 и 7000 порт.
Опция sequence содержит последовательность портов, по умолчанию используется протокол tcp, если вы необходимо использовать udp то необходимо задать его через двоеточие
sequence = 7000:tcp,8000:udp,9000:udp
В seq_timeout указывается значение в секундах за которое клиенту необходимо завершить всю последовательность обращения к портам. Устанавливая данный параметр нужно учитывать возможные задержки каналов связи.
<meta charset="utf-8">seq_timeout= 5
В command задается путь и параметры вызываемой программы в случае обнаружения корректной последовательности.
<meta charset="utf-8">command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags — определяет TCP-флаги пакетов, которые будут участвовать в последовательности, syn рекомендуется использовать совместно с SSH, так как SSH-трафик может мешать knockd, делая последовательность недействительной.
<meta charset="utf-8">tcpflags = syn
Если же вам необходимо открыть порт на определенный промежуток времени то можно использовать опции start_command и stop_command которые определяют команды которые должен выполнить knoсkd с интервалом указанном в опции cmd_timeout. Принцип действия следующий — получив указанную последовательность выполняется команда из опции start_command, а по истечении заданного промежутка времени выполняется команда stop_command.
В примере ниже объединены последовательности [openSSH] и [closeSSH] в одну последовательность c именем [10minSSH] и интервалом предоставления доступа к порту равном 10 минут
<meta charset="utf-8">[10minSSH]
sequence = 7000,8000,9000
seq_timeout = 5
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
cmd_timeout = 600
tcpflags = syn
После внесения всех настроек, сохраняем файл и запускаем службу knockd
service knockd start
После запуска проверяем статус службы и нет ли ошибок
<meta charset="utf-8">service knockd status
● knockd.service - Port-Knock Daemon
Loaded: loaded (/lib/systemd/system/knockd.service; disabled; vendor preset: enabled)
Active: active (running) since Wed 2022-01-26 11:56:40 UTC; 2s ago
Docs: man:knockd(1)
Main PID: 6331
Tasks: 1 (limit: 1066)
Memory: 320.0K
CGroup: /system.slice/knockd.service
└─6331 /usr/sbin/knockd
Jan 26 11:56:40 unixhosttest1.example.com systemd[1]: Started Port-Knock Daemon.
Jan 26 11:56:40 unixhosttest1.example.com knockd[6331]: starting up, listening on enp0s3
Подключение к серверу
Для того чтобы «достучаться» к закрытому порту необходимо выполнить запрос на ту цепочку портов которая указана в конфигурационном файле и сделать это можно либо используя утилиту которая есть почти в любой системе — telnet либо специальный клиент knock.
Для открытия порта используя telnet последовательно выполняем следующие команды
telnet 192.168.1.98 7000
telnet 192.168.1.98 8000
telnet 192.168.1.98 9000
Если вы уложились в заданный промежуток времени seq_timeout то на сервере на который мы «стучались» в статусе службы вы статус успешного прохождения цепочки и команду которая была выполнена
service knockd status
Jan 27 09:35:33 unixhost knockd[6735]: 192.168.1.99: openSSH: Stage 1
Jan 27 09:35:36 unixhost knockd[6735]: 192.168.1.99: openSSH: Stage 2
Jan 27 09:35:39 unixhos knockd[6735]: 192.168.1.99: openSSH: Stage 3
Jan 27 09:35:39 unixhost knockd[6735]: 192.168.1.99: openSSH: OPEN SESAME
Jan 27 09:35:39 unixhost knockd[38167]: openSSH: running command: /sbin/iptables -A INPUT -s 192.168.1.99 -p tcp --dport 22 -j ACCEPT
Для закрытия порта выполняем команду в обратном порядке
<meta charset="utf-8">telnet 192.168.1.98 9000
telnet 192.168.1.98 8000
telnet 192.168.1.98 7000
Утилита knock уменьшает количество вводимых команд до одной, достаточно перечислить все порты которые необходимо простучать. Для открытия порта необходимо выполнить
knock <meta charset="utf-8">192.168.1.98 7000 8000 9000
А для закрытия
knock <meta charset="utf-8">192.168.1.98 9000 8000 7000
Особенности
В подобном способе защиты есть пару нюансов которые необходимо знать перед тем как настраивать подобный способ защиты на своих серверах.
- knock работает по принципу демона, если демон knockd по каким-то причинам перестанет работать, то доступ к нужным портам будет невозможен.
- Если Ваш трафик будет прослушиваться то вычислить правильную цепочку не составит труда и чем чаше вы будете использовать port knocking тем легче это будет сделать