Prieteni, salutare!
Există multe modalități de a vă conecta de acasă la spațiul de lucru de la birou. Una dintre ele este utilizarea Microsoft Remote Desktop Gateway. Acesta este RDP peste HTTP. Nu vreau să ating aici configurarea RDGW în sine, nu vreau să discut de ce este bine sau rău, să-l tratăm ca pe unul dintre instrumentele de acces la distanță. Vreau să vorbesc despre protejarea serverului tău RDGW de Internetul rău. Când am configurat serverul RDGW, am devenit imediat îngrijorat de securitate, în special de protecția împotriva forței brute a parolei. Am fost surprins că nu am găsit niciun articol pe Internet despre cum să fac asta. Ei bine, va trebui să o faci singur.
RDGW în sine nu are nicio protecție. Da, poate fi expus cu o interfață goală la o rețea albă și va funcționa grozav. Dar acest lucru va face să fie neliniștit administratorul potrivit sau specialistul în securitatea informațiilor. În plus, vă va permite să evitați situația de blocare a contului, când un angajat neatent și-a amintit parola pentru un cont corporativ de pe computerul său de acasă, apoi și-a schimbat parola.
O modalitate bună de a proteja resursele interne de mediul extern este prin diferite proxy-uri, sisteme de publicare și alte WAF-uri. Să ne amintim că RDGW este încă http, atunci doar cere să conectați o soluție specializată între serverele interne și Internet.
Știu că există F5, A10, Netscaler (ADC). În calitate de administrator al unuia dintre aceste sisteme, voi spune că este posibil să se configureze și protecție împotriva forței brute pe aceste sisteme. Și da, aceste sisteme vă vor proteja și de orice inundație syn.
Dar nu orice companie își poate permite să achiziționeze o astfel de soluție (și să găsească un administrator pentru un astfel de sistem :), dar în același timp se pot ocupa de securitate!
Este complet posibil să instalați o versiune gratuită de HAProxy pe un sistem de operare gratuit. Am testat pe Debian 10, versiunea haproxy 1.8.19 în depozitul stabil. L-am testat și pe versiunea 2.0.xx din depozitul de testare.
Vom lăsa configurarea debian în sine în afara domeniului de aplicare al acestui articol. Pe scurt: pe interfața albă, închideți totul, cu excepția portului 443, pe interfața gri - conform politicii dvs., de exemplu, închideți totul, cu excepția portului 22. Deschideți doar ceea ce este necesar pentru lucru (VRRP de exemplu, pentru ip flotant).
În primul rând, am configurat haproxy în modul SSL bridging (alias modul http) și am activat înregistrarea pentru a vedea ce se întâmplă în interiorul RDP. Ca să spun așa, am ajuns la mijloc. Deci, calea /RDWeb specificată în „toate” articolele despre configurarea RDGateway lipsește. Tot ce este acolo este /rpc/rpcproxy.dll și /remoteDesktopGateway/. În acest caz, cererile standard GET/POST nu sunt utilizate; este folosit propriul lor tip de solicitare RDG_IN_DATA, RDG_OUT_DATA.
Nu mult, dar măcar ceva.
Să testăm.
Lansez mstsc, merg la server, văd patru erori 401 (neautorizate) în jurnale, apoi introdu numele meu de utilizator/parola și văd răspunsul 200.
Îl opresc, îl pornesc din nou și în jurnale văd aceleași patru erori 401. Intru autentificare/parolă greșită și văd din nou patru erori 401. De asta am nevoie. Asta vom prinde.
Deoarece nu a fost posibilă determinarea adresei URL de conectare și, în plus, nu știu cum să prind eroarea 401 în haproxy, voi prinde (nu prind de fapt, ci număr) toate erorile 4xx. Potrivit și pentru rezolvarea problemei.
Esența protecției va fi că vom număra numărul de erori 4xx (pe backend) pe unitatea de timp și dacă depășește limita specificată, atunci respingem (pe front-end) toate conexiunile ulterioare de la acest ip pentru timpul specificat .
Din punct de vedere tehnic, aceasta nu va fi protecție împotriva parolei forței brute, ci va fi protecție împotriva erorilor 4xx. De exemplu, dacă solicitați adesea o adresă URL inexistentă (404), atunci și protecția va funcționa.
Cea mai simplă și eficientă modalitate este de a conta pe backend și de a raporta dacă apare ceva în plus:
frontend fe_rdp_tsc
bind *:443 ssl crt /etc/haproxy/cert/desktop.example.com.pem
mode http
...
default_backend be_rdp_tsc
backend be_rdp_tsc
...
mode http
...
#создать таблицу, строковую, 1000 элементов, протухает через 15 сек, записать кол-во ошибок за последние 10 сек
stick-table type string len 128 size 1k expire 15s store http_err_rate(10s)
#запомнить ip
http-request track-sc0 src
#запретить с http ошибкой 429, если за последние 10 сек больше 4 ошибок
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
...
server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02
Nu este cea mai bună opțiune, hai să o complicăm. Vom conta pe backend și vom bloca pe front.
Vom trata atacatorul nepoliticos și îi vom renunța la conexiunea TCP.
frontend fe_rdp_tsc
bind *:443 ssl crt /etc/haproxy/cert/ertelecom_ru_2020_06_11.pem
mode http
...
#создать таблицу ip адресов, 1000 элементов, протухнет через 15 сек, сохрянять из глобального счётчика
stick-table type ip size 1k expire 15s store gpc0
#взять источник
tcp-request connection track-sc0 src
#отклонить tcp соединение, если глобальный счётчик >0
tcp-request connection reject if { sc0_get_gpc0 gt 0 }
...
default_backend be_rdp_tsc
backend be_rdp_tsc
...
mode http
...
#создать таблицу ip адресов, 1000 элементов, протухнет через 15 сек, сохранять кол-во ошибок за 10 сек
stick-table type ip size 1k expire 15s store http_err_rate(10s)
#много ошибок, если кол-во ошибок за 10 сек превысило 8
acl errors_too_fast sc1_http_err_rate gt 8
#пометить атаку в глобальном счётчике (увеличить счётчик)
acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
#обнулить глобальный счётчик
acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
#взять источник
tcp-request content track-sc1 src
#отклонить, пометить, что атака
tcp-request content reject if errors_too_fast mark_as_abuser
#разрешить, сбросить флажок атаки
tcp-request content accept if !errors_too_fast clear_as_abuser
...
server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02
același lucru, dar politicos, vom returna eroarea http 429 (Too Many Requests)
frontend fe_rdp_tsc
...
stick-table type ip size 1k expire 15s store gpc0
http-request track-sc0 src
http-request deny deny_status 429 if { sc0_get_gpc0 gt 0 }
...
default_backend be_rdp_tsc
backend be_rdp_tsc
...
stick-table type ip size 1k expire 15s store http_err_rate(10s)
acl errors_too_fast sc1_http_err_rate gt 8
acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
http-request track-sc1 src
http-request allow if !errors_too_fast clear_as_abuser
http-request deny deny_status 429 if errors_too_fast mark_as_abuser
...
Verific: lansez mstsc și încep să introduc la întâmplare parole. După a treia încercare, în 10 secunde mă dă înapoi și mstsc dă o eroare. După cum se vede în jurnalele.
Explicații. Sunt departe de a fi un maestru haproxy. Nu înțeleg de ce, de exemplu
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
vă permite să faceți aproximativ 10 greșeli înainte de a funcționa.
Sunt confuz cu privire la numerotarea contoarelor. Maeștri ai haproxy, mă voi bucura dacă mă completați, mă corectați, mă faceți mai bun.
În comentarii puteți sugera și alte modalități de a proteja RD Gateway, va fi interesant de studiat.
În ceea ce privește Windows Remote Desktop Client (mstsc), este de remarcat faptul că nu suportă TLS1.2 (cel puțin în Windows 7), așa că a trebuit să părăsesc TLS1; nu suportă cifra actuală, așa că a trebuit să le las și pe cele vechi.
Pentru cei care nu înțeleg nimic, doar învață și doresc deja să facă bine, vă voi oferi întreaga configurație.
haproxy.conf
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
#ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE
-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
#ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
ssl-default-bind-options no-sslv3
ssl-server-verify none
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 15m
timeout server 15m
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend fe_rdp_tsc
bind *:443 ssl crt /etc/haproxy/cert/dektop.example.com.pem
mode http
capture request header Host len 32
log global
option httplog
timeout client 300s
maxconn 1000
stick-table type ip size 1k expire 15s store gpc0
tcp-request connection track-sc0 src
tcp-request connection reject if { sc0_get_gpc0 gt 0 }
acl rdweb_domain hdr(host) -i beg dektop.example.com
http-request deny deny_status 400 if !rdweb_domain
default_backend be_rdp_tsc
backend be_rdp_tsc
balance source
mode http
log global
stick-table type ip size 1k expire 15s store http_err_rate(10s)
acl errors_too_fast sc1_http_err_rate gt 8
acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
tcp-request content track-sc1 src
tcp-request content reject if errors_too_fast mark_as_abuser
tcp-request content accept if !errors_too_fast clear_as_abuser
option forwardfor
http-request add-header X-CLIENT-IP %[src]
option httpchk GET /
cookie RDPWEB insert nocache
default-server inter 3s rise 2 fall 3
server rdgw01 192.168.1.33:443 maxconn 1000 weight 10 ssl check cookie rdgw01
server rdgw02 192.168.2.33:443 maxconn 1000 weight 10 ssl check cookie rdgw02
frontend fe_stats
mode http
bind *:8080
acl ip_allow_admin src 192.168.66.66
stats enable
stats uri /stats
stats refresh 30s
#stats admin if LOCALHOST
stats admin if ip_allow_admin
De ce două servere pe backend? Pentru că așa poți face toleranță la greșeală. Haproxy poate face și două cu un ip alb plutitor.
Resurse de calcul: puteți începe cu „două gig, două nuclee, PC de jocuri”. Conform
referințe:
Sursa: www.habr.com