通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

同事們大家好! 今天,當圍繞“遠程工作”的熱情稍稍消退,大多數管理員贏得了員工遠程訪問公司網絡的任務時,是時候分享我長期以來在提高VPN安全性方面的經驗了。 這篇文章現在不會流行IPSec IKEv2和xAuth。 這是關於建立一個系統。 雙因素身份驗證 (2FA) 當 MikroTik 充當 VPN 服務器時的 VPN 用戶。 即,當使用“經典”協議(例如 PPP)時。

通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

今天我將告訴您如何保護 MikroTik PPP-VPN,即使用戶帳戶被“劫持”。 當這個方案被介紹給我的一位客戶時,他簡短地描述道:“好吧,現在就像在銀行一樣!”。

該方法不使用外部驗證器服務。 這些任務由路由器本身在內部執行。 連接客戶端無需付費。 該方法適用於PC客戶端和移動設備。

一般保護方案如下:

  1. 成功連接VPN服務器的用戶的內部IP地址將自動列入灰名單。
  2. 連接事件會自動生成一個一次性代碼,該代碼會使用一種可用方法發送給用戶。
  3. 此列表中的地址對本地網絡資源的訪問受到限制,但“身份驗證器”服務除外,該服務正在等待接收一次性密碼。
  4. 提供代碼後,用戶就可以訪問網絡的內部資源。

第一 我必鬚麵對的最小問題是存儲用戶的聯繫信息以便向他發送 2FA 代碼。 由於無法在 Mikrotik 中創建與用戶相對應的任意數據字段,因此使用現有的“評論”字段:

/ppp 秘密添加名稱=Petrov 密碼=4M@ngr! 評論=“89876543210”

第二個 問題變得更加嚴重——交付代碼的路徑和方法的選擇。 目前實施了三種方案: a) 通過 USB 調製解調器發送短信 b) 電子郵件 c) 通過電子郵件發送短信,可供紅色蜂窩運營商的企業客戶使用。

是的,短信方案會帶來成本。 但如果你仔細觀察,就會發現“安全總是與金錢有關”(c)。
我個人不喜歡電子郵件方案。 不是因為它要求郵件服務器可供正在驗證的客戶端使用 - 分割流量不是問題。 但是,如果客戶不小心將 VPN 和電子郵件密碼保存在瀏覽器中,然後丟失了筆記本電腦,則攻擊者將獲得對公司網絡的完全訪問權限。

因此,我們決定 - 我們使用短信發送一次性代碼。

第三 問題出在哪裡 如何在 MikroTik 中生成 2FA 的偽隨機代碼。 RouterOS 腳本語言中沒有類似的 random() 函數,我之前見過幾個拐杖腳本偽隨機數生成器。 由於各種原因,我不喜歡他們中的任何一個。

事實上,MikroTik 中有一個偽隨機序列生成器! 在 /certificates scep-server 的上下文中,從表面上看它是隱藏的。 第一種方法 獲取一次性密碼既簡單又簡單 - 使用命令 /certificates scep-server otp 生成。 如果我們執行簡單的變量賦值操作,我們將獲得一個數組值,稍後可以在腳本中使用。

第二種方式 獲取一次性密碼,該密碼也很容易應用 - 使用外部服務 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 控制台中顯示變量。

第四個問題 必須快速解決這個問題 - 這就是連接的客戶端在身份驗證的第二階段傳輸其一次性代碼的方式和位置。

通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

MikroTik 路由器上必須有一個服務可以接受代碼並將其與特定客戶端進行匹配。 如果提供的代碼與預期相符,則客戶的地址應包含在某個“白”名單中,該名單中的地址將被允許訪問公司的內部網絡。

由於服務選擇不佳,決定使用 Mikrotik 內置的網絡代理通過 http 接受代碼。 由於防火牆可以使用動態 IP 地址列表,因此防火牆會執行代碼搜索,將其與客戶端 IP 進行匹配,並使用 Layer7 正則表達式將其添加到“白”列表中。 路由器本身已被分配一個條件 DNS 名稱“gw.local”,已在其上創建靜態 A 記錄以發布給 PPP 客戶端:

DNS
/ip dns static add 名稱=gw.本地地址=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. 授權成功後,將客戶端瀏覽器重定向至通知授權成功的頁面或圖片:

代理配置
/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. 接口列表“2fa” - 客戶端接口的動態列表,來自該接口的流量需要在 2FA 內進行處理;
  2. 地址列表“2fa_jailed”-VPN 客戶端隧道 IP 地址的“灰色”列表;
  3. address_list "2fa_approved" - 已成功通過雙因素身份驗證的 VPN 客戶端的隧道 IP 地址“白”列表。
  4. 防火牆鏈“input_2fa” - 它檢查 TCP 數據包是否存在授權代碼,並將代碼發送者的 IP 地址與所需的 IP 地址進行匹配。 鏈中的規則是動態添加和刪除的。

數據包處理的簡化流程圖如下所示:

通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

為了對來自“灰”名單中尚未通過第二階段身份驗證的客戶端的流量進行第 7 層檢查,已在標準“輸入”鏈中創建了一條規則:

代碼
/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 服務器,也可以應用於單個用戶。 同時,分配給用戶的配置文件具有優先權,用其指定的參數覆蓋為整個服務器選擇的配置文件的參數。

通過這種方法,我們可以為雙因素身份驗證創建一個特殊的配置文件,並將其分配給那些認為有必要這樣做的用戶,而不是所有用戶。 如果您不僅使用 PPP 服務連接最終用戶,而且同時建立站點到站點連接,這可能是相關的。

在新創建的特殊配置文件中,我們將連接用戶的地址和接口動態添加到地址和接口的“灰”列表中:

Winbox
通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

代碼
/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

有必要同時使用“地址列表”和“接口列表”列表來檢測和捕獲來自 dstnat(預路由)鏈中非輔助 VPN 客戶端的流量。

準備工作完成後,將創建額外的防火牆鍊和配置文件,我們將編寫一個腳本,負責自動生成 2FA 代碼和單獨的防火牆規則。

文檔 wiki.mikrotik.com PPP-Profile 為我們提供了與 PPP 客戶端連接-斷開事件相關的變量信息 “在用戶登錄事件上執行腳本。 這些是事件腳本可訪問的可用變量:用戶、本地地址、遠程地址、主叫方 ID、被叫方 ID、接口”。 其中一些對我們非常有用。

PPP 開啟連接事件配置文件中使用的代碼

#Логируем для отладки полученные переменные 
: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 開啟-關閉連接事件配置文件中使用的代碼

: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
通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

代碼
/ppp secrets set [find name=Petrov] profile=2FA

它在客戶端的外觀如何。

建立 VPN 連接後,帶有 SIM 卡的 Android/iOS 手機/平板電腦會收到如下短信:

短信
通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

如果直接從手機/平板電腦建立連接,則只需單擊消息中的鏈接即可完成 2FA。 很舒服。

如果 VPN 連接是從 PC 建立的,則用戶將需要輸入最少的密碼形式。 設置 VPN 時,會向用戶提供 HTML 文件形式的小表格。 該文件甚至可以通過郵件發送,以便用戶保存它並在方便的地方創建快捷方式。 它看起來像這樣:

桌子上的標籤
通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

用戶單擊該快捷方式,將打開一個簡單的代碼輸入表單,該表單會將代碼粘貼到打開的 URL 中:

屏幕形式
通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

以最原始的形式為例。 有需要的可以自行修改。

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 徽標,這應該表示身份驗證成功:

通過 MikroTik 和 SMS 對 VPN 用戶進行雙因素身份驗證

請注意,圖像是使用 WebProxy Deny Redirect 從內置 MikroTik Web 服務器返回的。

我想可以使用“熱點”工具自定義圖像,上傳您自己的版本並使用 WebProxy 設置拒絕重定向 URL。

對於那些試圖以 20 美元購買最便宜的“玩具”Mikrotik 並用它替換 500 美元路由器的人來說,這是一個很大的要求 - 不要這樣做。 像“hAP Lite”/“hAP mini”(家庭接入點)這樣的設備的CPU(smips)非常弱,它們很可能無法應對業務部分的負載。

警告! 該解決方案有一個缺點:當客戶端連接或斷開連接時,配置會發生更改,路由器會嘗試將其保存在其非易失性內存中。 由於大量客戶端以及頻繁的連接和斷開連接,這可能會導致路由器內部存儲性能下降。

PS:只要你的編程能力足夠,向客戶端交付代碼的方法是可以擴展和補充的。 例如,您可以向 telegram 發送消息或...建議選項!

我希望這篇文章對您有用,並有助於使中小型企業的網絡更加安全。

來源: www.habr.com