Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Вітаю колеги! Сьогодні, коли розпал пристрастей навколо «віддалення» трохи спав, більшість адмінів перемогли завдання віддаленого доступу співробітників до корпоративної мережі, настав час поділитися моїм давнім напрацюванням з підвищення безпеки VPN. У цій статті не буде модних нині IPSec IKEv2 та xAuth. Йтиметься про побудову системи двофакторної аутентифікації (2FA) користувачів VPN, коли MikroTik виступає як VPN-сервер. А саме коли використовуються «класичні» протоколи типу PPP.

Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Сьогодні я розповім як захистити MikroTik PPP-VPN навіть у разі «викрадення» власної обліку. Коли ця схема була впроваджена одному з моїх замовників, він охарактеризував його коротко «ну тепер прямо як у банку!».

Метод не використовує зовнішніх сервісів-автентифікаторів. Завдання виконуються внутрішніми засобами маршрутизатора. Без витрат для клієнта, що підключається. Спосіб працює як для клієнтів PC, так і для мобільних пристроїв.

Загальна схема захисту виглядає так:

  1. Внутрішня IP-адреса користувача, який успішно підключився до VPN-сервера, автоматично потрапляє в «сірий» список.
  2. Подія підключення автоматично генерує одноразовий код, який надсилається користувачеві одним з доступних способів.
  3. Адресам, які знаходяться в цьому списку, обмежений доступ до ресурсів локальної мережі, за винятком сервісу «аутентифікатора», який очікує на отримання одноразового коду-паролю.
  4. Після пред'явлення коду користувачу відкривається доступ до внутрішніх ресурсів мережі.

перша найменша проблема з якою довелося зіткнутися, це зберігання контактної інформації користувача для пересилання йому коду 2FA. Оскільки довільних полів даних, відповідних користувачам у мікротиці створити не можна, було використано існуюче поле «comment»:

/ppp secrets add name=Petrov password=4M@ngr! comment=«89876543210»

Друга проблема виявилася серйознішою - вибір шляху та способу доставки коду. В даний момент реалізовано три схеми: а) SMS через USB-модем; б) e-mail; в) SMS via e-mail доступний для корпоративних клієнтів червоного стільникового оператора.

Так, схеми із SMS приносять витрати. Але якщо розібратися, «безпека завжди про гроші» (с).
Схема з e-mail мені особисто не подобається. Не тому, що вимагає доступності поштового сервера для клієнта, що аутентифікується, — це не проблема розділити трафік. Однак, якщо клієнт безпечно зберігав паролі на і на vpn і на пошту в браузері, а потім втратив свій ноутбук, зловмисник отримає повний доступ до корпоративної мережі.

Отже, вирішено – доставляємо одноразовий код за допомогою SMS-повідомлень.

третя проблема була в тому, де і як у MikroTik згенерувати псевдовипадковий код для 2FA. У скриптовій мові RouterOS немає аналога функції random() і раніше я бачив кілька милиць скриптових генераторів псевдовипадкових чисел. Жоден із них мені не сподобався з різних причин.

Насправді, генератор псевдовипадкових послідовностей у MikroTik Є! Схований він від поверхового погляду в контексті /certificates scep-server. Перший спосіб отримати одноразовий пароль легкий і простий - командою /certificates scep-server otp generate. Якщо виконати просту операцію присвоєння змінної, ми отримаємо значення типу array, яке можна використовувати надалі у скриптах.

Другий спосіб отримання одноразового пароля, який теж легко застосувати — використання зовнішнього сервісу random.org для генерації бажаного виду послідовності псевдовипадкових чисел. Ось спрощений консольний приклад отримання даних у змінну:

Код
: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

Запит сформатований для консолі (у тілі скрипта потрібно екранування спецсимволів) отримує рядок із шести символів-цифр у змінну $rnd1. Наступна команда "put" просто відображає змінну в консолі MikroTik.

Четверта проблема яку довелося оперативно вирішувати - це яким чином і куди підключений клієнт передаватиме свій одноразовий код на другій стадії аутентифікації.

Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

На роутері MikroTik повинна бути служба здатна прийняти код і порівняти його з конкретним клієнтом. При збігу наданого коду з очікуваною адресою клієнта має потрапити до якогось «білого» списку, адресам з якого дозволено доступ до внутрішньої мережі компанії.

Зважаючи на небагатий вибір служб, було прийнято рішення приймати коди по http за допомогою вбудованого в мікротик webproxy. А оскільки фаєрвол вміє працювати з динамічними списками IP-адрес, то пошук коду, зіставлення його з клієнтським IP і внесення до «білого» списку виконує саме фаєрвол за допомогою Layer7 regexp. Самому маршрутизатору надано умовне DNS-ім'я «gw.local», на ньому створено статичний А-запис для видачі PPP-клієнтам:

DNS
/ip dns static add name=gw.local address=172.31.1.1

Захоплення на проксі трафіку неперевірених клієнтів:
/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

У цьому випадку проксі має дві функції.

1. Відкривати tcp-з'єднання з клієнтами;

2. У разі успішної авторизації переадресувати клієнтський браузер на сторінку або картинку, що сповіщає про успішне проходження аутентифікації:

Proxy config
/ip proxy
set enabled=yes port=3128
/ip proxy access
add action=deny disabled=no redirect-to=gw.local./mikrotik_logo.png src-address=0.0.0.0/0

Перелічу важливі елементи конфігурації:

  1. interface-list "2fa" - динамічний список клієнтських інтерфейсів, трафік з яких вимагає обробки в рамках 2FA;
  2. address-list "2fa_jailed" - "сірий" список тунельних IP-адрес клієнтів VPN;
  3. address_list «2fa_approved» — «білий» список тунельних IP-адрес клієнтів VPN, які успішно пройшли двофакторну автентифікацію.
  4. ланцюжок фаєрвола «input_2fa» — у ньому відбувається перевірка tcp-пакетів на наявність коду авторизації та збіг IP-адреси відправника коду з необхідним. Правила в ланцюжок додаються та видаляються динамічно.

Спрощена блок-схема обробки пакета виглядає так:

Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Для попадання в перевірку по Layer7 трафіку від клієнтів із «сірого» списку ще не пройшли другий етап аутентифікації, у стандартному ланцюжку «input» створено правило:

Код
/ip firewall filter add chain=input !src-address-list=2fa_approved action=jump jump-target=input_2fa

Тепер почнемо прикручувати це багатство до сервісу PPP. MikroTik дозволяє використовувати скрипти в профілях (ppp-profile) та призначати їх на події встановлення та розриву ppp-з'єднання. Налаштування ppp-profile можуть бути використані як для PPP-сервера в цілому, так і для окремих користувачів. При цьому призначений користувачеві profile має пріоритет перекриваючи своїми заданими параметрами параметри вибраного для сервера в цілому.

В результаті такого підходу ми можемо створити спеціальний профіль для двофакторної аутентифікації та призначити його не всім користувачам, а лише тим, кому вважаємо за потрібне це зробити. Це може бути актуальним у разі, якщо служби PPP у вас використовуються не тільки для підключення кінцевих користувачів, але одночасно і для побудови site-to-site з'єднань.

У новоствореному спеціальному профілі використовуємо динамічне додавання адреси та інтерфейсу користувача, що підключився, в «сірі» списки адрес та інтерфейсів:

winbox
Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Код
/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

Використовувати спільно списки address-list і interface-list необхідно, щоб визначати і захоплювати трафік від не пройшли вторинну авторизацію VPN-клієнтів в ланцюжку dstnat (prerouting).

Коли підготовка закінчена, додаткові ланцюжки фаєрволу та профіль створені, напишемо скрипт, що відповідає за автогенерацію коду 2FA та окремих правил фаєрволу.

Документація wiki.mikrotik.com на PPP-Profile збагачує нас інформацією про змінні, пов'язані з подіями підключення-відключення PPP-клієнта «Execute script on user login-event. Ці є варіаційні параметри, які є accessible для event script: user, local-address, remote-address, call-id, called-id, interface». Деякі з них нам знадобляться.

Код, який використовується у профілі для події підключення PPP on-up

#Логируем для отладки полученные переменные 
:log info (

quot;local-address")
:log info (


quot;remote-address")
:log info (


quot;caller-id")
:log info (


quot;called-id")
:log info ([/int pptp-server get (


quot;interface") name])
#Объявляем свои локальные переменные
:local listname "2fa_jailed"
:local viamodem false
:local modemport "usb2"
#ищем автоматически созданную запись в адрес-листе "2fa_jailed"
:local recnum1 [/ip fi address-list find address=(


quot;remote-address") 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 ("Your code: ".$comm1."n Or open 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 [email protected] [email protected] subject="@".$vphone body=$msgboby }

#Генерируем Layer7 regexp
local vregexp ("otp\/".$comm1)
:local vcomment ("2fa_".(


quot;remote-address"))
/ip firewall layer7-protocol add name=(


quot;vcomment") comment=(


quot;remote-address") 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;remote-address") dst-limit=1,1,src-address/1m40s

Спеціально для любителів бездумно копіпастити попереджаю — код взято з тестової версії і може містити незначні очеп'ятки. Розібратися де саме розуміє людині праці не складе.

При відключенні користувача генерується подія On-Down і викликається відповідний скрипт з параметрами. Завдання цього скрипта - почистити за собою правила фаєрвола, створені для користувача, що відключився.

Код, який використовується у профілі для події підключення PPP on-down

:local vcomment ("2fa_".(

quot;remote-address"))
/ip firewall address-list remove [find address=(


quot;remote-address") list=2fa_approved] /ip firewall filter remove [find chain="input_2fa" src-address=(


quot;remote-address") ] /ip firewall layer7-protocol remove [find name=$vcomment]
Після цього можна створювати користувачів і призначати всім або деяким із них профіль з двофакторною автентифікацією.

winbox
Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Код
/ppp secrets set [find name=Petrov] profile=2FA

Як це виглядає за клієнта.

При встановленні VPN-з'єднання, на телефон/планшет на андроїд/iOS з сім-картою надходить SMS приблизно такого вигляду:

SMSка
Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Якщо з'єднання встановлено безпосередньо з телефону/планшета, то можна пройти 2FA просто натиснувши посилання з повідомлення. Це зручно.

Якщо VPN-з'єднання встановлюється з PC, то для користувача буде потрібно мінімальна форма введення пароля. Невелика форма у вигляді HTML-файлу передається користувачеві при налаштуванні VPN. Файлик можна навіть поштою переслати, щоб користувач зберіг його у себе та створив ярлик у зручному місці. Приблизно так це виглядає:

Ярлик на столі
Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Користувач клацає мишкою по ярлику, відкривається проста форма введення коду, яка вставить код у URL, що відкривається:

Скрин форми
Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Форма найпримітивніша, дана для прикладу. Охочі можуть доопрацювати під себе.

2fa_login_mini.html

<html>
<head> <title>SMS OTP login</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head>
<body>
<form name="login" action="location.href='http://gw.local/otp/'+document.getElementById(‘text').value"  method="post"
 <input id="text" type="text"/> 
<input type="button" value="Login" onclick="location.href='http://gw.local/otp/'+document.getElementById('text').value"/> 
</form>
</body>
</html>

Якщо авторизація пройшла успішно, користувач у браузері побачить лого MikroTik, що має послужити сигналом про успішну аутентифікацію:

Двофакторна автентифікація користувачів VPN за допомогою MikroTik та SMS

Зауважу, що картинка повертається із вбудованого web-сервера MikroTik за допомогою WebProxy Deny Redirect.

Вважаю, картинку можна кастомізувати, використовуючи інструмент «hotspot», завантаживши туди свій варіант і поставивши на нього Deny Redirect URL з WebProxy.

Велике прохання до тих, хто намагається купивши найдешевший «іграшковий» мікротик за $20, замінити ним маршрутизатор за $500 — не треба так чинити. Пристрої типу "hAP Lite" / "hAP mini" (home access point) мають дуже слабкий CPU (smips), і ймовірно не впораються з навантаженням в бізнес-сегменті.

Увага! Дане рішення має один мінус: при підключенні-відключенні клієнтів відбуваються зміни конфігурації, яку маршрутизатор намагається зберігати у своїй незалежній пам'яті. При великій кількості клієнтів та частих підключеннях-відключеннях, це може призвести до деградації внутрішнього накопичувача в маршрутизаторі.

PS: методи доставки коду клієнту можуть бути розширені та доповнені наскільки вистачить ваших можливостей у програмуванні. Наприклад, можна надсилати повідомлення в telegram або пропонуйте варіанти!

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

Джерело: habr.com