Hei, venner!
Det finnes mange måter å koble seg fra hjemmet til arbeidsplassen på kontoret. En av dem er å bruke Microsoft Remote Desktop Gateway. Dette er RDP over HTTP. Jeg ønsker ikke å gå inn på hvordan man konfigurerer RDGW her, eller diskutere hvorfor det er bra eller dårlig, la oss behandle det som et av verktøyene for fjernadgang. Jeg vil snakke om hvordan du kan beskytte RDGW-serveren din mot den onde internettverden. Da jeg satt opp RDGW-serverne, begynte jeg umiddelbart å tenke på sikkerhet, spesielt beskyttelse mot passordknekking. Jeg ble overrasket over at jeg ikke fant artikler på nettet om hvordan dette kan gjøres. Vel, det ser ut til at jeg må gjøre det selv.
Selve RDGW har ingen innebygde beskyttelser. Ja, det kan settes opp med bare grensesnittet i det åpne nettet og vil fungere fint. Men en ordentlig administrator eller sikkerhetsekspert vil ikke føle seg trygg med det. I tillegg kan det forhindre situasjoner med blokkerte kontoer, når en uaktsom ansatt husker passordet til bedriftens konto på sin hjemmedatamaskin og deretter endrer sitt eget passord.
En god måte å beskytte interne ressurser mot eksterne trusler på, er gjennom proxyer, publiseringssystemer og andre WAF-løsninger. Husk at RDGW til syvende og sist er http, så det er naturlig å installere en spesialisert løsning mellom interne servere og internett.
Jeg vet at det finnes avanserte løsninger som F5, A10, Netscaler(ADC). Som administrator for et av disse systemene kan jeg si at det også er mulig å konfigurere beskyttelse mot passordknekking på disse systemene. Og ja, disse systemene vil samtidig beskytte deg mot syn flood-angrep.
Men langt fra alle selskaper har råd til å kjøpe en slik løsning (og finne en administrator for et slikt system :), men sikkerheten kan de ta seg av!
Det er fullt mulig å installere en gratis versjon av HAProxy på et gratis operativsystem. Jeg har testet det på Debian 10, og i det stabile depositories er versjonen haproxy 1.8.19. Jeg har også sjekket versjoner 2.0.xx fra testing repository.
Vi lar konfigurasjonen av selve Debian være utenfor artikkelen. Kort oppsummert: på det åpne grensesnittet, lås alt bortsett fra port 443, og på det grå grensesnittet - i henhold til din policy, for eksempel også låse alt bortsett fra port 22. Bare åpne det som er nødvendig for drift (VRRP for eksempel, for flyttbar IP).
Først konfigurerte jeg haproxy i SSL bridging mode (også kjent som mode http) og aktiverte logging for å se hva som skjer med RDP. Med andre ord, jeg plasserte meg midt i det. Så, stien som er nevnt i «alle» artikler om konfigurasjon av RDGateway, /RDWeb, finnes ikke. Alt som er der, er /rpc/rpcproxy.dll og /remoteDesktopGateway/. Standard GET/POST forespørselen brukes ikke, det brukes en egen forespørselstype RDG_IN_DATA, RDG_OUT_DATA.
Ikke mye, men noe.
La oss teste.
Jeg kjører mstsc, går til serveren, og ser fire 401 (unauthorized) feil i loggene, deretter skriver jeg inn brukernavn/passord og ser svar 200.
Jeg kobler fra, starter på nytt, og i loggene ser jeg de samme fire 401 feilene. Jeg skriver inn feil brukernavn/passord og ser igjen fire 401 feil. Dette er det vi skal overvåke.
Siden jeg ikke klarte å identifisere login URL-en, og jeg heller ikke vet hvordan man kan fange opp 401-feilen i haproxy, vil jeg fange opp (egentlig telle) alle 4xx feilene. Det vil også være tilstrekkelig for å løse oppgaven.
Essensen av beskyttelsen vil være at vi vil telle antall 4xx feil (på backend) over en tidsenhet, og hvis det overskrider en spesifisert grense, vil vi avvise (på frontend) alle videre forbindelser fra denne IP-en i den angitte tidsperioden.
Teknisk sett vil dette ikke være en beskyttelse mot passordprøver, men en beskyttelse mot 4xx feil. For eksempel, hvis man ofte ber om en ikke-eksisterende URL (404), vil beskyttelsen også aktivere.
Den enkleste og mest fungerende metoden er å telle opp og avvise på backend, hvis det skulle dukke opp noe overflødig:
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
...
#opprett en tabell, teksttype, 1000 elementer, utløper etter 15 sek, lagre antall feil de siste 10 sek
stick-table type string len 128 size 1k expire 15s store http_err_rate(10s)
#huske ip
http-request track-sc0 src
#forby med http-feil 429, hvis det er mer enn 4 feil de siste 10 sek
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
Ikke den beste løsningen, la oss gjøre det mer komplisert. Vi vil telle på backend, mens vi blokkerer på frontend.
Vi vil håndtere angriperen brutalt ved å kutte TCP-tilkoblingen hans.
frontend fe_rdp_tsc
bind *:443 ssl crt /etc/haproxy/cert/ertelecom_ru_2020_06_11.pem
mode http
...
#laga IP-adresser, 1000 elementer, utløper etter 15 sekunder, lagre fra den globale telleren
stick-table type ip size 1k expire 15s store gpc0
#få kilde
tcp-request connection track-sc0 src
#avvise tcp-tilkoblingen hvis den globale telleren >0
tcp-request connection reject if { sc0_get_gpc0 gt 0 }
...
default_backend be_rdp_tsc
backend be_rdp_tsc
...
mode http
...
#laga IP-adresser, 1000 elementer, utløper etter 15 sekunder, lagre antall feil de siste 10 sek
stick-table type ip size 1k expire 15s store http_err_rate(10s)
#mange feil, hvis antall feil de siste 10 sek oversteget 8
acl errors_too_fast sc1_http_err_rate gt 8
#markere angrep i den globale telleren (øke telleren)
acl mark_as_abuser sc0_inc_gpc0(fe_rdp_tsc) gt 0
#nullstille den globale telleren
acl clear_as_abuser sc0_clr_gpc0(fe_rdp_tsc) ge 0
#få kilde
tcp-request content track-sc1 src
#avvise, merke som angrep
tcp-request content reject if errors_too_fast mark_as_abuser
#tillate, tilbakestille angrepsflagget
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
det samme, men på en høflig måte, vi vil returnere HTTP-feil 429 (For mange forespørsler)
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
...
Jeg sjekker: kjører mstsc og begynner å skrive inn passord tilfeldig. Etter det tredje forsøket på 10 sekunder blir jeg kastet ut, og mstsc gir en feil. Dette vises i loggene.
Forklaringer. Jeg er på ingen måte en mester i haproxy. Jeg forstår ikke hvorfor, for eksempel
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
tillater omtrent 10 feil før det aktiveres.
Jeg blir forvirret av nummereringen av tellerne. Haprosy-mestre, jeg vil sette pris på om dere kan supplere meg, rette meg, eller gjøre det bedre.
I kommentarene kan du nevne andre måter å beskytte RD Gateway på, det vil være interessant å studere.
Når det gjelder Windows Remote Desktop Client (mstsc), er det verdt å merke seg at den ikke støtter TLS1.2 (i hvert fall i Windows 7), så jeg måtte bruke TLS1; den støtter ikke aktuelle cipher, så jeg måtte også beholde de gamle.
For those who haven’t understood anything yet and want to do it well, I will provide the entire configuration.
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
Why have two servers in the backend? Because this allows for fault tolerance. You can also set up HAProxy with two floating white IPs.
Computing resources: You can start with "two gigs, two cores, gaming PC." According to this will be sufficient with some margin.
Lenker:
Kilde: habr.com
