Приятели, здравейте!
Съществуват множество начини за свързване от вкъщи към работното място в офиса. Един от тях е да се използва Microsoft Remote Desktop Gateway. Това е RDP върху HTTP. Не искам тук да разглеждам настройката на самия RDGW, нито да обсъждам защо е добър или лош, нека го разглеждаме като един от инструментите за отдалечен достъп. Искам да говоря за защитата на вашия RDGW сървър от злонамерен интернет. Когато настроих RDGW сървърите, веднага се притесних за защитата, особено за защитата срещу подбора на пароли. Изненадах се, че не намерих статии в интернет за това как може да се направи. Е, ще трябва да се справя сам.
Самият RDGW няма никаква защита. Да, може да бъде изложен с гол интерфейс в откритата мрежа и ще работи прекрасно. Но на добрия администратор или специалист по информационна безопасност това ще му създаде неудобство. Освен това ще избегнете ситуацията с блокирането на акаунта, когато небрежен служител е запомнил паролата на корпоративния акаунт на домашния си компютър и след това е сменил паролата си.
Добър начин за защита на вътрешните ресурси от външната среда са различни проксита, системи за публикуване и други WAF. Нека си припомним, че RDGW все пак е http, така че направо извиква да се включи специализирано решение между вътрешните сървъри и интернет.
Знам, че има страхотни F5, A10, Netscaler(ADC). Като администратор на една от тези системи, ще кажа, че е възможно да се настрои защита от подбор и на тези системи. И да, тези системи ще ви защитят и от всякакъв син флуд.
Но не всяка компания може да си позволи да закупи подобно решение (и да намери администратор за такава система :), а за безопасността може да се погрижи!
Напълно възможно е да се инсталира безплатна версия на HAProxy на безплатна операционна система. Тествах на Debian 10, в стабилния репозиторий версия haproxy 1.8.19. Също така проверявах на версии 2.0.xx от testing репозитория.
Настройката на самия Debian оставяме извън обсъждането. Накратко: на белия интерфейс да закрием всичко, освен порта 443, на сивия интерфейс — според вашата политика, например също да закрием всичко, освен порта 22. Да отворим само това, което е необходимо за работа (например VRRP за плаващ ip).
На първо място конфигурирах haproxy в режим SSL bridging (т.е. режим http) и активирах логовете, за да видя какво става в RDP. С други думи, влезнах в средата. Но посоченият в „всички“ статии за настройка на RDGateway път /RDWeb липсва. Всичко, което има, е /rpc/rpcproxy.dll и /remoteDesktopGateway/. При това не се използват стандартни GET/POST заявки, а свой тип заявка RDG_IN_DATA, RDG_OUT_DATA.
Не много, но поне нещо.
Нека тестваме.
Стартирам mstsc, отивам на сървъра, в логовете виждам четири грешки 401 (неупълномощен), след което въвеждам логин/парола и виждам отговор 200.
Изключвам, стартирам отново, в логовете виждам същите четири грешки 401. Ввеждам грешен логин/парола и отново виждам четири грешки 401. Това е, което ни трябва. Ще го улавяме.
Тъй като не успях да определя URL адреса за вход, и освен това не знам как да улавям точно грешка 401 в haproxy, ще улавям (всъщност няма да улавям, а ще броя) всички грешки 4xx. И това ще е приемливо за решаване на задачата.
Същността на защитата ще се състои в това, че ще броим броя на грешки 4xx (на backend) за единица време и ако той надхвърли зададения праг, то ще отказваме (на frontend) всички по-нататъшни връзки от този IP за указаното време.
Технически, това няма да бъде защита от подбиране на паролата, а защита от грешки 4xx. Например, ако често се запитва не съществуващ URL (404), то защитата също ще сработи.
Най-простият и работещ начин е на backend да се броят и отблъскват, ако нещо излишно се е появило:
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
Не е най-добрият вариант, ще усложним. Ще броим на backend, а блокираме на frontend.
С атакуващия ще постъпим грубо, ще прекъсваме 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
същата работа, но учтиво, ще връщаме грешка 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
...
Проверявам: стартирам mstsc и започвам произволно да въвеждам пароли. След третия опит за 10 сек. ме изритва, а mstsc издава грешка. Както се вижда в логовете.
Пояснения. Аз не съм експерт по haproxy. Не разбирам, например, защо
http-request deny deny_status 429 if { sc_http_err_rate(0) gt 4 }
позволява около 10 грешки, преди да сработи.
Заплетен съм в номерирането на броячите. Мастери на haproxy, ще се радвам, ако ме допълните, поправите или направите по-добре.
В коментарите можете да предложите други методи за защита на RD Gateway, ще бъде интересно да се проучат.
Що се отнася до клиента за отдалечен работен плот на Windows (mstsc), трябва да се отбележи, че той не поддържа TLS1.2 (поне в Windows 7), затова трябваше да оставя TLS1; не поддържа актуални шифри, затова също така трябваше да оставя старите.
За тези, които нищо не разбираха и вече искат да правят добре, ще представя цялата конфигурация.
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
# Локации на SSL материали по подразбиране
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Вижте: 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
Защо два сървъра на бекенда? Защото така може да се направи отказоустойчивост. Haproxy може да настроите и два с плаващ бял IP.
Изчислителните ресурси: може да започнете с "две гига, два ядра, игрови ПК". Според това ще бъде повече от достатъчно.
Линкове:
Източник: habr.com
