Вітаю колеги! Сьогодні, коли розпал пристрастей навколо «віддалення» трохи спав, більшість адмінів перемогли завдання віддаленого доступу співробітників до корпоративної мережі, настав час поділитися моїм давнім напрацюванням з підвищення безпеки VPN. У цій статті не буде модних нині IPSec IKEv2 та xAuth. Йтиметься про побудову системи
Сьогодні я розповім як захистити MikroTik PPP-VPN навіть у разі «викрадення» власної обліку. Коли ця схема була впроваджена одному з моїх замовників, він охарактеризував його коротко «ну тепер прямо як у банку!».
Метод не використовує зовнішніх сервісів-автентифікаторів. Завдання виконуються внутрішніми засобами маршрутизатора. Без витрат для клієнта, що підключається. Спосіб працює як для клієнтів PC, так і для мобільних пристроїв.
Загальна схема захисту виглядає так:
- Внутрішня IP-адреса користувача, який успішно підключився до VPN-сервера, автоматично потрапляє в «сірий» список.
- Подія підключення автоматично генерує одноразовий код, який надсилається користувачеві одним з доступних способів.
- Адресам, які знаходяться в цьому списку, обмежений доступ до ресурсів локальної мережі, за винятком сервісу «аутентифікатора», який очікує на отримання одноразового коду-паролю.
- Після пред'явлення коду користувачу відкривається доступ до внутрішніх ресурсів мережі.
перша найменша проблема з якою довелося зіткнутися, це зберігання контактної інформації користувача для пересилання йому коду 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, яке можна використовувати надалі у скриптах.
Другий спосіб отримання одноразового пароля, який теж легко застосувати — використання зовнішнього сервісу
Код
: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.
Четверта проблема яку довелося оперативно вирішувати - це яким чином і куди підключений клієнт передаватиме свій одноразовий код на другій стадії аутентифікації.
На роутері 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
Перелічу важливі елементи конфігурації:
- interface-list "2fa" - динамічний список клієнтських інтерфейсів, трафік з яких вимагає обробки в рамках 2FA;
- address-list "2fa_jailed" - "сірий" список тунельних IP-адрес клієнтів VPN;
- address_list «2fa_approved» — «білий» список тунельних IP-адрес клієнтів VPN, які успішно пройшли двофакторну автентифікацію.
- ланцюжок фаєрвола «input_2fa» — у ньому відбувається перевірка tcp-пакетів на наявність коду авторизації та збіг IP-адреси відправника коду з необхідним. Правила в ланцюжок додаються та видаляються динамічно.
Спрощена блок-схема обробки пакета виглядає так:
Для попадання в перевірку по 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 з'єднань.
У новоствореному спеціальному профілі використовуємо динамічне додавання адреси та інтерфейсу користувача, що підключився, в «сірі» списки адрес та інтерфейсів:
Код
/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 та окремих правил фаєрволу.
Код, який використовується у профілі для події підключення 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
Код
/ppp secrets set [find name=Petrov] profile=2FA
Як це виглядає за клієнта.
При встановленні VPN-з'єднання, на телефон/планшет на андроїд/iOS з сім-картою надходить SMS приблизно такого вигляду:
SMSка
Якщо з'єднання встановлено безпосередньо з телефону/планшета, то можна пройти 2FA просто натиснувши посилання з повідомлення. Це зручно.
Якщо VPN-з'єднання встановлюється з PC, то для користувача буде потрібно мінімальна форма введення пароля. Невелика форма у вигляді HTML-файлу передається користувачеві при налаштуванні VPN. Файлик можна навіть поштою переслати, щоб користувач зберіг його у себе та створив ярлик у зручному місці. Приблизно так це виглядає:
Ярлик на столі
Користувач клацає мишкою по ярлику, відкривається проста форма введення коду, яка вставить код у URL, що відкривається:
Скрин форми
Форма найпримітивніша, дана для прикладу. Охочі можуть доопрацювати під себе.
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, що має послужити сигналом про успішну аутентифікацію:
Зауважу, що картинка повертається із вбудованого 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