MS Remote Desktop Gateway, HAProxy և գաղտնաբառի կոպիտ ուժ

Ընկերներ, բարև:

Կան բազմաթիվ եղանակներ՝ տնից ձեր գրասենյակի աշխատանքային տարածքին միանալու համար: Դրանցից մեկը Microsoft Remote Desktop Gateway-ի օգտագործումն է: Սա RDP է HTTP-ի վրա: Ես չեմ ուզում այստեղ անդրադառնալ ինքնին RDGW-ի տեղադրմանը, չեմ ուզում քննարկել, թե ինչու է դա լավ կամ վատ, եկեք դրան վերաբերվենք որպես հեռավոր մուտքի գործիքներից մեկին: Ես ուզում եմ խոսել ձեր RDGW սերվերը չար ինտերնետից պաշտպանելու մասին: Երբ ես ստեղծեցի RDGW սերվերը, ես անմիջապես մտահոգվեցի անվտանգության, հատկապես գաղտնաբառի կոպիտ ուժի դեմ պաշտպանությունից: Ես զարմացա, որ ինտերնետում հոդվածներ չգտա, թե ինչպես դա անել: Դե, դուք պետք է դա անեք ինքներդ:

RDGW-ն ինքնին չունի որևէ պաշտպանություն: Այո, այն կարող է բաց ինտերֆեյսի միջոցով հայտնվել սպիտակ ցանցի հետ, և այն հիանալի կաշխատի: Բայց դա անհանգիստ կդարձնի ճիշտ ադմինիստրատորին կամ տեղեկատվական անվտանգության մասնագետին: Բացի այդ, դա թույլ կտա խուսափել հաշիվների արգելափակման իրավիճակից, երբ անզգույշ աշխատակիցը հիշել է իր տան համակարգչի կորպորատիվ հաշվի գաղտնաբառը, իսկ հետո փոխել գաղտնաբառը։

Ներքին ռեսուրսները արտաքին միջավայրից պաշտպանելու լավ միջոց է տարբեր վստահված անձանց, հրատարակչական համակարգերի և այլ WAF-ների միջոցով: Հիշենք, որ RDGW-ն դեռ http է, այնուհետև այն պարզապես խնդրում է միացնել մասնագիտացված լուծում ներքին սերվերների և ինտերնետի միջև:

Ես գիտեմ, որ կան թույն F5, A10, Netscaler(ADC): Որպես այս համակարգերից մեկի ադմինիստրատոր, ես կասեմ, որ հնարավոր է նաև այս համակարգերի վրա բիրտ ուժի դեմ պաշտպանություն ստեղծել: Եվ այո, այս համակարգերը նաև կպաշտպանեն ձեզ ցանկացած սինթետիկ ջրհեղեղից:

Բայց ոչ ամեն ընկերություն կարող է իրեն թույլ տալ նման լուծում գնել (և գտնել ադմինիստրատոր նման համակարգի համար :), բայց միևնույն ժամանակ նրանք կարող են հոգ տանել անվտանգության մասին:

HAProxy-ի անվճար տարբերակը լիովին հնարավոր է տեղադրել անվճար օպերացիոն համակարգի վրա: Ես փորձարկեցի Debian 10-ի վրա, հապրոքսի տարբերակ 1.8.19 կայուն պահոցում: Ես նաև փորձարկեցի այն փորձարկման պահոցից 2.0.xx տարբերակով:

Մենք ինքնին debian-ի կարգավորումը կթողնենք այս հոդվածի շրջանակներից դուրս: Հակիրճ. սպիտակ ինտերֆեյսի վրա փակեք ամեն ինչ, բացի 443 պորտից, մոխրագույն ինտերֆեյսի վրա - ըստ ձեր քաղաքականության, օրինակ, փակեք նաև ամեն ինչ, բացի պորտից 22-ից: Բացեք միայն այն, ինչ անհրաժեշտ է աշխատանքի համար (VRRP, օրինակ, լողացող ip-ի համար):

Նախ, ես կարգավորեցի հապրոքսիան SSL-ի կամրջման ռեժիմում (aka http ռեժիմ) և միացրեցի գրանցումը, որպեսզի տեսնեմ, թե ինչ է կատարվում RDP-ի ներսում: Այսպես ասած, ես մտա մեջտեղը։ Այսպիսով, RDGateway-ի ստեղծման «բոլոր» հոդվածներում նշված /RDWeb ուղին բացակայում է: Այն ամենը, ինչ կա, կա /rpc/rpcproxy.dll և /remoteDesktopGateway/: Այս դեպքում ստանդարտ GET/POST հարցումները չեն օգտագործվում, օգտագործվում է իրենց սեփական տիպի հարցումը RDG_IN_DATA, RDG_OUT_DATA:

Ոչ շատ, բայց գոնե ինչ-որ բան:

Եկեք փորձարկենք.

Ես գործարկում եմ mstsc-ն, գնում եմ սերվեր, տեսնում եմ չորս 401 (չթույլատրված) սխալ տեղեկամատյաններում, այնուհետև մուտքագրում եմ իմ օգտվողի անունը/գաղտնաբառը և տեսնում եմ պատասխանը 200:

Ես անջատում եմ այն, նորից սկսում, և գրանցամատյաններում տեսնում եմ նույն չորս 401 սխալները: Մուտքագրում եմ սխալ մուտք/գաղտնաբառ և նորից տեսնում եմ չորս 401 սխալ: Դա այն է, ինչ ինձ պետք է: Սա այն է, ինչ մենք բռնելու ենք:

Քանի որ հնարավոր չէր որոշել մուտքի url-ը, և բացի այդ, ես չգիտեմ, թե ինչպես բռնել 401 սխալը հապրոքսիայում, ես կբռնեմ (իրականում ոչ թե կբռնեմ, այլ կհաշվեմ) բոլոր 4xx սխալները: Հարմար է նաև խնդրի լուծման համար։

Պաշտպանության էությունը կլինի այն, որ մենք հաշվելու ենք 4xx սխալների քանակը (հետին պլանում) մեկ միավորի համար, և եթե այն գերազանցում է նշված սահմանը, ապա մերժում ենք (առջևի մասում) այս ip-ի բոլոր հետագա միացումները նշված ժամանակով: .

Տեխնիկապես սա պաշտպանություն չի լինի գաղտնաբառի կոպիտ ուժից, դա կլինի պաշտպանություն 4xx սխալներից: Օրինակ, եթե դուք հաճախ պահանջում եք գոյություն չունեցող url (404), ապա պաշտպանությունը նույնպես կաշխատի:

Ամենապարզ և ամենաարդյունավետ միջոցը հետին պլանի վրա հույս դնելն է և եթե որևէ ավելորդ բան հայտնվի, ետ զեկուցեք.

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

Լավագույն տարբերակը չէ, եկեք բարդացնենք: Մենք կհաշվենք հետնամասի վրա և արգելափակելու ենք ճակատային մասում:

Մենք կոպտորեն կվերաբերվենք հարձակվողին և կթողնենք նրա 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 սխալը (չափազանց շատ հարցումներ)

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-ը սխալ է տալիս։ Ինչպես երեւում է տեղեկամատյաններում.

Բացատրություններ. Ես հեռու եմ հապրոքսի վարպետից: Չեմ հասկանում, թե ինչու, օրինակ
http- հարցումը մերժել deny_status 429, եթե { sc_http_err_rate(0) gt 4 }
թույլ է տալիս գործել մոտ 10 սխալ, նախքան այն աշխատելը:

Ես շփոթված եմ հաշվիչների համարակալման հարցում։ Հապրոքսիայի վարպետներ, ուրախ կլինեմ, եթե ինձ լրացնեք, ուղղեք, ավելի լավը դարձնեք։

Մեկնաբանություններում կարող եք առաջարկել RD Gateway-ի պաշտպանության այլ ուղիներ, հետաքրքիր կլինի ուսումնասիրել։

Ինչ վերաբերում է Windows Remote Desktop Client-ին (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

        # 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

Ինչու՞ երկու սերվեր հետնամասում: Որովհետև այսպես կարելի է սխալների հանդուրժողականություն ցուցաբերել: Haproxy-ը կարող է նաև լողացող սպիտակ ip-ով երկու պատրաստել:

Համակարգչային ռեսուրսներ. կարող եք սկսել «երկու կոնցեռնից, երկու միջուկից, խաղային համակարգչից»: Համաձայն Վիքիպեդիա սա բավական կլինի խնայելու համար:

Հղումներ.

rdp-gateway-ի կարգավորում HAProxy-ից
Միակ հոդվածը, որը ես գտա, որտեղ նրանք անհանգստանում էին գաղտնաբառի կոպիտ ուժով

Source: www.habr.com

Добавить комментарий