Dzień dobry, koledzy! Dziś, gdy napięcie związane z „pracą zdalną” nieco opadło, większość administratorów rozwiązała problem zdalnego dostępu pracowników do sieci korporacyjnej. Nadszedł czas, aby podzielić się moim doświadczeniem w zwiększaniu bezpieczeństwa VPN. W tym artykule nie będzie mowy o modnych obecnie IPSec IKEv2 i xAuth. Omówimy budowę systemu użytkowników VPN, gdy MikroTik działa jako serwer VPN. A dokładnie, gdy wykorzystywane są „klasyczne” protokoły takie jak PPP.

Dziś opowiem, jak zabezpieczyć MikroTik PPP-VPN nawet w przypadku „przechwycenia” konta użytkownika. Gdy ten schemat został wdrożony u jednego z moich klientów, określił to krótko: „no, teraz jak w banku!”.
Metoda nie wykorzystuje zewnętrznych usług uwierzytelniających. Zadania są realizowane za pomocą wewnętrznych środków samego routera. Bez dodatkowych kosztów dla podłączającego się klienta. Metoda działa zarówno dla klientów PC, jak i dla urządzeń mobilnych.
Ogólny schemat ochrony wygląda następująco:
- Wewnętrzny adres IP użytkownika, który pomyślnie połączył się z serwerem VPN, automatycznie trafia na „szary” listę.
- Zdarzenie połączenia automatycznie generuje jednorazowy kod, który jest przesyłany użytkownikowi jednym z dostępnych sposobów.
- Adresy znajdujące się na tej liście mają ograniczony dostęp do zasobów lokalnej sieci, z wyjątkiem usługi „uwierzytelniającej”, która czeka na otrzymanie jednorazowego kodu hasła.
- Po przedstawieniu kodu użytkownik uzyskuje dostęp do wewnętrznych zasobów sieci.
Pierwsza Najmniejszym problemem, z którym musiałem się zmierzyć, było przechowywanie informacji kontaktowych użytkownika do przesyłania mu kodu 2FA. Ponieważ nie można stworzyć własnych pól danych odpowiadających użytkownikom w MikroTik, wykorzystano istniejące pole „komentarz”:
/ppp secrets add name=Petrov password=4M@ngr! comment=«89876543210»
Drugi Problem okazał się poważniejszy — wybór drogi i sposobu dostarczenia kodu. Aktualnie zrealizowano trzy schematy: a) SMS przez modem USB b) e-mail c) SMS przez e-mail dostępny dla klientów korporacyjnych czerwonego operatora komórkowego.
Tak, schematy z SMS-ami generują koszty. Ale jeśli się zastanowić, „bezpieczeństwo to zawsze kwestia pieniędzy” (c).
Schemat z e-mailem osobiście mi się nie podoba. Nie dlatego, że wymaga dostępności serwera pocztowego dla uwierzytelnionego klienta — nie jest to problem podzielić ruch. Jednak, jeśli klient nieostrożnie przechowuje hasła zarówno na VPN, jak i w przeglądarce oraz następnie zgubi laptopa, haker zyska pełny dostęp do sieci korporacyjnej.
Zatem zdecydowano — dostarczamy jednorazowy kod za pomocą wiadomości SMS.
Trzeci problem polegał na tym, gdzie i jak w MikroTik wygenerować pseudolosowy kod dla 2FA. W języku skryptowym RouterOS nie ma odpowiednika funkcji random() i wcześniej widziałem kilka improwizowanych skryptów do generowania pseudolosowych liczb. Żaden z nich mi się nie podobał z różnych powodów.
W rzeczywistości generator pseudolosowych sekwencji w MikroTik JUŻ JEST! Jest ukryty przed powierzchownym spojrzeniem w kontekście /certificates scep-server. Pierwszy sposób uzyskanie jednorazowego hasła jest łatwe i proste — komendą /certificates scep-server otp generate. Jeśli wykonamy prostą operację przypisania zmiennej, uzyskamy wartość typu tablica, którą można wykorzystać w dalszych skryptach.
Drugi sposób uzyskania jednorazowego hasła, które również łatwo zastosować — użycie zewnętrznego serwisu do generowania pożądanego rodzaju sekwencji pseudolosowych liczb. Oto uproszczony przykład uzyskania danych w zmiennej:
Kod
:global rnd1 [:pick ([/tool fetch url="https://www.random.org/strings/?num=1&len=7&digits=on&unique=on&format=plain&rnd=new" as-value output=user ]->"da
ta") 1 6]
:put $rnd1
Zapytanie sformatowane dla konsoli (w treści skryptu będzie konieczne zescapowanie znaków specjalnych) uzyskuje ciąg sześciu cyfr w zmiennej $rnd1. Następna komenda „put” po prostu wyświetla zmienną w konsoli MikroTik.
Czwarty problem, który trzeba było szybko rozwiązać — to w jaki sposób i dokąd podłączony klient będzie przesyłał swój jednorazowy kod na drugim etapie uwierzytelnienia.

Na routerze MikroTik powinna istnieć usługa zdolna do przyjęcia kodu i powiązania go z konkretnym klientem. Przy zgodności podanego kodu z oczekiwanym, adres klienta powinien znaleźć się na liście „białej”, z której zezwala się na dostęp do wewnętrznej sieci firmy.
Z powodu ubogiego wyboru usług podjęto decyzję o przyjmowaniu kodów przez http za pomocą wbudowanego w MikroTik webproxy. Ponieważ zapora ogniowa potrafi pracować z dynamicznymi listami adresów IP, wyszukiwanie kodu, dopasowywanie go do adresu IP klienta i dodawanie do "białej" listy wykonuje właśnie zapora ogniowa za pomocą Layer7 regexp. Routerowi nadano warunkową nazwę DNS "gw.local", na którym stworzono statyczny rekord A do wydawania PPP-klientom:
DNS
/ip dns static add name=gw.local address=172.31.1.1
Przechwytywanie ruchu proxy niezaufanych klientów:
/ip firewall nat add chain=dstnat dst-port=80,443 in-interface=2fa protocol=tcp !src-address-list=2fa_approved action=redirect to-ports=3128
W tym przypadku proxy ma dwie funkcje.
1. Nawiązywanie połączeń tcp z klientami;
2. W przypadku pomyślnej autoryzacji przekierowanie przeglądarki klienta na stronę lub obrazek informujący o pomyślnej autoryzacji:
Konfiguracja proxy
/ip proxy
ustawienie enabled=yes port=3128
/ip proxy access
dodaj akcję=deny wyłączone=no przekierowanie-do=gw.local./mikrotik_logo.png adres-źródłowy=0.0.0.0/0
Wypiszę ważne elementy konfiguracji:
- interface-list „2fa” — dynamiczna lista interfejsów klientów, których ruch wymaga przetwarzania w ramach 2FA;
- address-list „2fa_jailed” — „szara” lista tunelowych adresów IP klientów VPN;
- address_list „2fa_approved” — „biała” lista tunelowych adresów IP klientów VPN, którzy pomyślnie przeszli dwuetapową autoryzację.
- łańcuch zapory ogniowej „input_2fa” — w nim odbywa się weryfikacja pakietów tcp pod kątem obecności kodu autoryzacji oraz dopasowania adresu IP nadawcy kodu do wymaganego. Reguły w łańcuchu są dodawane i usuwane dynamicznie.
Uproszczony schemat blokowy przetwarzania pakietu wygląda tak:
Aby ruch z klientów z "szarej" listy, którzy jeszcze nie przeszli drugiego etapu autoryzacji, mógł przejść kontrolę za pomocą Layer7, w standardowym łańcuchu „input” stworzono regułę:
Kod
/ip firewall filter add chain=input !src-address-list=2fa_approved action=jump jump-target=input_2fa
Teraz zaczynamy łączyć te wszystkie elementy z usługą PPP. MikroTik pozwala na korzystanie z skryptów w profilach (ppp-profile) i przypisywanie ich do zdarzeń nawiązywania i przerywania połączenia ppp. Ustawienia ppp-profile mogą być stosowane zarówno dla serwera PPP jako całości, jak i dla poszczególnych użytkowników. Przypisany użytkownikowi profil ma priorytet, zastępując parametry profilu wybranego dla serwera jako całości.
Dzięki temu podejściu możemy stworzyć specjalny profil dla uwierzytelniania dwuetapowego i przypisać go nie wszystkim użytkownikom, ale tylko tym, którzy są uznawani za potrzebujących tego. Może to być istotne, jeśli usługi PPP są używane nie tylko do łączenia końcowych użytkowników, ale także do budowy połączeń site-to-site.
W nowo utworzonym specjalnym profilu korzystamy z dynamicznego dodawania adresu i interfejsu podłączającego się użytkownika do „szarych” list adresów i interfejsów:
winbox
Kod
/ppp profile add address-list=2fa_jailed change-tcp-mss=no local-address=192.0.2.254 name=2FA interface-list=2fa only-one=yes remote-address=dhcp_pool1 use-compression=no use-encryption= required use-mpls=no use-upnp=no dns-server=172.31.1.1
Korzystanie wspólnie z listami „address-list” i „interface-list” jest konieczne, aby określać i przechwytywać ruch od klientów VPN, którzy nie przeszli wtórnej autoryzacji w łańcuchu dstnat (prerouting).
Gdy przygotowania są zakończone, dodatkowe łańcuchy zapory i profil są utworzone, napiszemy skrypt odpowiedzialny za automatyczną generację kodu 2FA i poszczególnych reguł zapory.
na PPP-Profile dostarcza nam informacji o zmiennych związanych z zdarzeniami połączenia-rozłączenia klienta PPP „Wykonaj skrypt podczas zdarzenia logowania użytkownika. Oto dostępne zmienne, które są dostępne w skrypcie zdarzenia: user, local-address, remote-address, caller-id, called-id, interface”. Niektóre z nich będą nam bardzo przydatne.
Kod używany w profilu dla zdarzenia połączenia PPP on-up
#Логируем для отладки полученные переменные :log info (quot;adres-lokalny")
:log info (quot;adres-zdalny")
:log info (quot;id-dzwoniący")
:log info (quot;id-odbierający")
:log info ([/int pptp-server get (quot;interfejs") name])
#Объявляем свои локальные переменные
:local listname "2fa_jailed"
:local viamodem false
:local modemport "usb2"
#ищем автоматически созданную запись в адрес-листе "2fa_jailed"
:local recnum1 [/ip fi address-list find address=(quot;adres-zdalny") list=$listname]
#получаем псевдослучайный код через random.org
#:local rnd1 [:pick ([/tool fetch url="https://www.random.org/strings/?num=1&len=7&digits=on&unique=on&format=plain&rnd=new" as-value output=user]->"data") 0 4]
#либо получаем псевдослучайный код через локальный генератор
#:local rnd1 [pick ([/cert scep-server otp generate as-value minutes-valid=1]->"password") 0 4 ]#Ищем и обновляем коммент к записи в адрес-листе. Вносим искомый код для отладки
/ip fir address-list set $recnum1 comment=$rnd1
#получаем номер телефона куда слать SMS
:local vphone [/ppp secret get [find name=$user] comment]#Готовим тело сообщения. Если клиент подключается к VPN прямо с телефона ему достаточно
#будет перейти прямо по ссылке из полученного сообщения
:local msgboby ("Twój kod: ".$comm1."n Lub otwórz link http://gw.local/otp/".$comm1."/")# Отправляем SMS по выбранному каналу - USB-модем или email-to-sms
if $viamodem do={
/tool sms send phone-number=$vphone message=$msgboby port=$modemport }
else={
/tool e-mail send server=a.b.c.d from=admin@mydomain.example to=mail2sms@mcommunicator.ru subject="@".$vphone body=$msgboby }#Генерируем Layer7 regexp
local vregexp ("otp\/".$comm1)
:local vcomment ("2fa_".quot;adres-zdalny"))
/ip firewall layer7-protocol add name=(quot;vcomment") comment=(
quot;adres-zdalny") regexp=(
quot;vregexp")
#Генерируем правило проверяющее по Layer7 трафик клиента в поисках нужного кода
#и небольшой защитой от брутфорса кодов с помощью dst-limit
/ip firewall filter add action=add-src-to-address-list address-list=2fa_approved address-list-timeout=none-dynamic chain=input_2fa dst-port=80,443,3128 layer7-protocol=(quot;vcomment") protocol=tcp src-address=(
quot;adres-zdalny") dst-limit=1,1,src-address/1m40s
Specjalnie dla tych, którzy myślą, że mogą kopiować i wklejać bez namysłu, ostrzegam — kod pochodzi z wersji testowej i może zawierać drobne błędy. Osobie, która wie, co robi, łatwo będzie zrozumieć, gdzie dokładnie.Podczas rozłączenia użytkownika generowane jest zdarzenie „On-Down” i wywoływany jest odpowiedni skrypt z parametrami. Zadaniem tego skryptu jest usunięcie reguł zapory stworzonych dla rozłączonego użytkownika.
Kod używany w profilu dla zdarzenia połączenia PPP on-down
:local vcomment ("2fa_".quot;adres-zdalny"))
/ip firewall address-list remove [find address=("adres zdalny") lista=2fa_approved]
/ip firewall filter remove [find chain="input_2fa" src-address=("adres zdalny") ]
/ip firewall layer7-protocol remove [find name=$vcomment]
Po tym można tworzyć użytkowników i przypisywać im profil z uwierzytelnianiem dwuetapowym wszystkim lub niektórym z nich.winbox
Kod
/ppp secrets set [find name=Petrov] profile=2FAJak to wygląda po stronie klienta.
Podczas nawiązywania połączenia VPN na telefonie/tablecie z systemem Android/iOS z kartą SIM przychodzi SMS w takim mniej więcej formacie:
SMSka
Jeśli połączenie nawiązywane jest bezpośrednio z telefonu/tabletu, można przejść 2FA, po prostu klikając link w wiadomości. To wygodne.
Jeśli połączenie VPN jest nawiązywane z komputerem PC, użytkownik będzie potrzebował minimalnej formy wprowadzenia hasła. Mała forma w postaci pliku HTML jest przesyłana do użytkownika podczas konfiguracji VPN. Plik można nawet przesłać pocztą, aby użytkownik mógł go zapisać i utworzyć skrót w dogodnym miejscu. Tak to wygląda:
Skrót na pulpicie
Użytkownik klika myszką na skrót, otwiera się prosta forma wprowadzenia kodu, która wstawi kod do otwieranego URL:
Zrzut ekranu formy
Forma jest najbardziej prymitywna, podana jako przykład. Zainteresowani mogą dostosować ją do swoich potrzeb.
2fa_login_mini.html
<html> <head> <title>Logowanie za pomocą SMS OTP</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form name="login" action="/pl/location.href='http://gw.local/otp/'+document.getElementById(‘text').value/" method="post" <input id="text" type="text" data-trp-original-action="location.href='http://gw.local/otp/'+document.getElementById(‘text').value"/><input type="hidden" name="trp-form-language" value="pl"/> <input type="button" value="Zaloguj się" onclick="location.href='http://gw.local/otp/'+document.getElementById('text').value"/> </form> </body> </html>Jeśli autoryzacja zakończy się powodzeniem, użytkownik w przeglądarce zobaczy logo MikroTik, co powinno służyć jako sygnał o pomyślnej autoryzacji:
Zauważam, że obrazek wraca z wbudowanego serwera www MikroTik za pomocą WebProxy Deny Redirect.
Uważam, że obrazek można dostosować, używając narzędzia „hotspot”, ładując tam swoją wersję i ustawiając dla niej Deny Redirect URL z WebProxy.
Proszę tych, którzy próbują wymienić najtańszego „zabawkowego” MikroTika za 20 $, na router za 500 $ — nie róbcie tego. Urządzenia typu „hAP Lite”/„hAP mini” (punkt dostępowy do domu) mają bardzo słaby CPU (smips) i mogą nie poradzić sobie z obciążeniem w segmencie biznesowym.
Uwaga! To rozwiązanie ma jeden minus: przy podłączaniu i odłączaniu klientów następują zmiany w konfiguracji, którą router stara się zachować w swojej pamięci nieulotnej. Przy dużej liczbie klientów i częstym podłączaniu i odłączaniu może to prowadzić do degradacji wewnętrznego magazynu w routerze.
P.S.: Metody dostarczania kodu klientowi mogą być rozszerzane i uzupełniane w miarę możliwości programowania. Na przykład można wysyłać wiadomości na Telegram lub… sugerować inne opcje!
Mam nadzieję, że artykuł okaże się pomocny i pomoże uczynić sieci małego i średniego biznesu jeszcze bezpieczniejszymi.
Źródło: habr.com




