fail2ban՝ brute-force հարձակվողների ban ըստ log-երի
Հետևիր log-երին, հաշվիր ձախողումները, ban արա IP-ն․ պարզ intrusion prevention SSH-ի և nginx-ի համար։
30 վայրկյանում
Յուրաքանչյուր public սերվեր ամբողջ օրը ստուգվում է bot-երի կողմից, որոնք գաղտնաբառեր են փորձում և scan են անում հայտնի խոցելի URL-ներ։ fail2ban-ը կարդում է քո log-երը, նկատում է IP, որը նորից ու նորից ձախողվում է, և որոշ ժամանակով արգելափակում է այդ IP-ն firewall-ում։ Այն էժան է, պարզ և արդյունավետ աղմկոտ, մեկ աղբյուրից եկող հարձակումների դեմ, բայց այն մի քանի շերտից մեկն է, ոչ թե ամբողջական պաշտպանություն։
Ինչու եմ օգտագործում
- Սերվերներիս վրա գործարկում եմ fail2ban, որովհետև այն լուռ հեռացնում է SSH-ի և վեբ login-ների դեմ brute-force աղմուկի մեծ մասը։
- Այն այն անվտանգության baseline-ի մասն է, որը կիրառում եմ յուրաքանչյուր սերվերի վրա՝ միայն key-երով SSH-ի, ufw-ի և ավտոմատ թարմացումների կողքին։
- Այն նաև log-երը նորից ընթեռնելի է դարձնում․ քիչ աղբ փորձեր նշանակում է, որ իրական խնդիրները աչքի են ընկնում։
Ինչպես է աշխատում
01Գաղափարը՝ անվտանգության աշխատակից, որը կարդում է հյուրերի գրքույկը
Պատկերացրու ակումբի անվտանգության աշխատակցի, որը մի քանի վայրկյանը մեկ ստուգում է գրանցամատյանը։ Եթե նույն մարդը տասը րոպեում հինգ անգամ սխալ գաղտնաբառ է փորձել, նրան մեկ ժամով մուտքը մերժվում է։ Դա fail2ban-ն է։ Տեխնիկապես այն Python daemon է, որը հետևում է log ֆայլերին կամ systemd journal-ին, յուրաքանչյուր նոր տող համեմատում է regular expression-ների հետ, հաշվում է համընկնումները ըստ IP հասցեի, և երբ շեմը հատվում է, գործարկում է action, սովորաբար ավելացնելով firewall կանոն (nftables, iptables կամ ufw), որը դեն է նետում հարձակվողի packet-ները։ Ban-ի ժամանակից հետո այն հեռացնում է կանոնը։ Սա կոչվում է log-based intrusion prevention․ այն ինքը traffic-ը չի զննում, այլ արձագանքում է նրան, ինչ քո ծառայություններն արդեն log են անում։ Դա այն դարձնում է թեթև և ծառայությունից անկախ․ ցանկացած բան, որը ձախողումները log է անում IP-ով, կարելի է պաշտպանել։
02Jail-եր, filter-ներ և action-ներ
fail2ban-ը կառուցված է երեք մասից։ Filter-ը (filter.d/*.conf) regular expression-ների հավաքածու է, որոնք ճանաչում են ձախողումը log տողում և <HOST> tag-ով բռնում են host-ը։ Action-ը (action.d/*.conf) ասում է, թե ինչ անել ban-ի և unban-ի ժամանակ՝ firewall կանոններ, Cloudflare API call, email։ Jail-ը միավորում է դրանք՝ որ log-ը կարդալ, որ filter-ն ու action-ն օգտագործել և շեմերը։ Շեմերը երեք թիվ են։ maxretry-ն այն է, թե քանի ձախողում է trigger անում ban։ findtime-ը այն պատուհանն է, որի ընթացքում այդ ձախողումները պետք է տեղի ունենան։ bantime-ը այն է, թե որքան է տևում ban-ը։ bantime.increment-ով կրկնվող խախտողները ամեն անգամ ավելի երկար ban են ստանում։ Recidive jail-ը գնում է ավելի հեռու․ այն հետևում է fail2ban-ի սեփական log-ին և օրերով ban է անում այն IP-ները, որոնք անընդհատ ban են ստանում։ Երբեք մի խմբագրիր jail.conf-ը, որը թարմացումները վերագրում են․ կարգավորումներդ դիր jail.local-ում կամ jail.d/*.local-ում։
- maxretry = 5, findtime = 10m, bantime = 1h-ը խելամիտ սկզբնակետ է։
- ignoreip-ը թույլ չի տալիս, որ քո գրասենյակի կամ VPN-ի հասցեները երբևէ ban ստանան։
- Ubuntu 24.04-ում և ավելի նորերում sshd jail-ը կարդում է systemd journal-ը (backend = systemd), ոչ թե /var/log/auth.log-ը։
03Գործնական jail.local SSH-ի և nginx-ի համար
Այս կոնֆիգուրացիան պաշտպանում է SSH-ը և nginx-ի տարածված դեպքերը՝ օգտագործելով fail2ban-ի հետ եկող filter-ները։ nginx-http-auth-ը բռնում է ձախողված basic-auth login-ները, nginx-botsearch-ը բռնում է bot-երին, որոնք պահանջում են հայտնի exploit ճանապարհներ, որոնք վերադարձնում են 404, իսկ nginx-limit-req-ը ban է անում client-ներին, որոնք անընդհատ հարվածում են nginx-ի rate limit-ին (աշխատում է միայն այն դեպքում, եթե կարգավորել ես limit_req)։ Recidive-ը մշակում է համառ հարձակվողներին։ Ubuntu-ում տեղադրիր apt install fail2ban-ով․ փաթեթն արդեն միացնում է sshd jail-ը jail.d/defaults-debian.conf-ի միջոցով nftables action-ով։ Խմբագրելուց հետո գործարկիր fail2ban-client reload և ստուգիր status-ը։ Եթե օգտագործում ես ufw և նախընտրում ես ban-երը տեսնել ufw status-ում, փոխարենը սահմանիր banaction = ufw։
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
[sshd]
enabled = true
backend = systemd
maxretry = 3
[nginx-http-auth]
enabled = true
[nginx-botsearch]
enabled = true
[recidive]
enabled = true
bantime = 1w
findtime = 1d
04Սեփական filter-ի գրում
Կարող ես պաշտպանել ցանկացած բան, որը log է անում ձախողումները։ Տարածված օրինակ՝ Laravel կամ Next.js կայք, որը անընդհատ ստուգվում է WordPress login էջերի և արտահոսած .env ֆայլերի համար։ Այդ request-ները երբեք օրինական չեն ոչ WordPress կայքի վրա, ուստի դրանցից մի քանիսը ուժեղ ազդանշան են։ Ստորև filter-ը համընկնում է այդպիսի request-ների հետ nginx-ի access log-ում (լռելյայն combined ձևաչափ, որտեղ client-ի IP-ն առաջին դաշտն է)։ Նոր filter-ը միացնելուց առաջ միշտ ստուգիր այն fail2ban-regex-ով իրական log-ի վրա․ այն ցույց է տալիս, թե քանի տող համընկավ, և բռնում է regex-ի սխալներ, որոնք ոչ ոքի ban չէին անի կամ բոլորին ban կանեին։ Եթե կայքը Cloudflare-ի կամ այլ proxy-ի հետևում է, նախ կարգավորիր nginx-ի real_ip մոդուլը, այլապես log-ը պարունակում է proxy-ի IP-ն, և դու ban կանես proxy-ն։
# /etc/fail2ban/filter.d/nginx-probe.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD) /(wp-login\.php|xmlrpc\.php|\.env|\.git/)
ignoreregex =
# /etc/fail2ban/jail.d/nginx-probe.local
[nginx-probe]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 1d
# Test before enabling
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-probe.conf
05Ստուգում, unban և debug
fail2ban-client-ը կառավարման գործիքն է։ status-ը ցույց է տալիս ակտիվ jail-երը, status-ը jail-ի անվամբ ցույց է տալիս ընթացիկ ձախողումները և ban արված IP-ները, իսկ set jail unbanip-ը հեռացնում է ban-ը (օրինակ՝ երբ գործընկերը չափազանց հաճախ սխալ է մուտքագրել իր գաղտնաբառը)։ fail2ban-ի log-ը՝ /var/log/fail2ban.log-ը, գրանցում է յուրաքանչյուր ban և unban jail-ի անվամբ, և դա առաջին տեղն է նայելու, երբ ինչ-որ մեկն ասում է, որ իր մուտքն արգելափակված է։ Եթե jail-ը երբեք ոչինչ ban չի անում, ստուգիր երեք բան․ jail-ն իսկապես միացված է (status-ը ցուցակում է այն), այն կարդում է ճիշտ աղբյուրը (log path կամ systemd backend), և filter-ն իսկապես համընկնում է տողերի հետ (fail2ban-regex)։ Եթե այն ban է անում, բայց traffic-ը դեռ գալիս է, action-ը կարող է չհամապատասխանել քո firewall-ին, կամ traffic-ը գալիս է proxy-ի միջով, որի IP-ն հարձակվողինը չէ։
sudo fail2ban-client status # list active jails
sudo fail2ban-client status sshd # failures and banned IPs for one jail
sudo fail2ban-client banned # all banned IPs, per jail
sudo fail2ban-client set sshd unbanip 203.0.113.10
sudo fail2ban-client unban 203.0.113.10 # remove from every jail
sudo fail2ban-client reload # apply config changes
sudo tail -f /var/log/fail2ban.log
sudo nft list ruleset | grep -A3 f2b # see the firewall rules it created
06Սահմանափակումներ, և fail2ban ընդդեմ CrowdSec-ի
fail2ban-ը հարձակումները տեսնում է միայն այն բանից հետո, երբ դրանք հայտնվում են log-ում, և յուրաքանչյուր IP-ն գնահատում է առանձին։ Հազարավոր հասցեներից բաշխված հարձակումը, որտեղ յուրաքանչյուրը փորձում է մեկ կամ երկու անգամ, երբեք չի հատում շեմը։ Այն ոչինչ չի անում քո հավելվածի խոցելիությունների դեմ, և սերվերի firewall-ում ban-ը չի օգնում, երբ traffic-ը գալիս է CDN proxy-ի միջով, որովհետև միացումը գալիս է CDN-ից․ այնտեղ քեզ պետք է action, որը արգելափակում է edge-ում (fail2ban-ը գալիս է Cloudflare action-ներով), կամ CDN-ի սեփական WAF կանոնները։ Այնպես որ դիտարկիր այն որպես աղմուկի նվազեցում իրական վերահսկողությունների վրա՝ միայն SSH key-եր, default-deny firewall, rate limit-եր nginx-ում և առջևում Cloudflare-ի նման WAF։ CrowdSec-ը ժամանակակից այլընտրանքն է․ այն log-երը parse է անում նմանատիպ ձևով, բայց հայտնաբերումն առանձնացնում է արգելափակումից (bouncer-ներ firewall-ի, nginx-ի կամ Cloudflare-ի համար) և ազդանշանները կիսում է իր համայնքի հետ, այնպես որ ուրիշների վրա հարձակվող IP-ն կարող է արգելափակվել, մինչև կհասնի քեզ։ Այն ավելի հզոր է՝ ավելի շատ շարժվող մասերով և online բաղադրիչով։
Օգտագործեք, երբ
- Բաց SSH-ով ցանկացած ինտերնետին նայող սերվերի վրա, նույնիսկ միայն key-երով login-ի դեպքում, log-ի աղմուկը կրճատելու և scanner-ները դանդաղեցնելու համար։
- Login ֆորմաների, basic-auth տարածքների և admin պանելների առջևում, որոնք ձախողումները log են անում client-ի IP-ով։
- Scanner-ներին ban անելու համար, որոնք ստուգում են քո կայքում երբեք գոյություն չունեցող ճանապարհներ (.env, wp-login.php, .git)։
- Որպես թեթև շերտ փոքր սերվերների վրա, որտեղ լիարժեք WAF-ը կամ SIEM-ը չափազանցություն կլիներ։
Մի՛ օգտագործեք, երբ
- Որպես հիմնական պաշտպանություն բաշխված հարձակումների կամ DDoS-ի դեմ․ օգտագործիր CDN/WAF և rate limiting։
- Proxy-ի կամ load balancer-ի հետևում՝ առանց real-IP կոնֆիգուրացիայի․ դու ban կանես հենց proxy-ն։
- Երբ SSH-ը հասանելի է միայն VPN-ի կամ private ցանցի միջով․ պաշտպանելու քիչ բան է մնում։
Այլընտրանքներ
- CrowdSec
Log-based հայտնաբերում առանձին bouncer-ներով և համայնքի ընդհանուր blocklist-ներով․ ավելի շատ հնարավորություններ, ավելի շատ բաղադրիչներ։
- sshguard
Ավելի փոքր, կենտրոնացված daemon SSH-ի և մի քանի ծառայության համար․ ավելի քիչ կարգավորելի, քան fail2ban-ը։
- Cloudflare WAF և rate limiting
Հարձակումները արգելափակում է edge-ում, մինչև դրանք կհասնեն սերվերին․ ծածկում է միայն HTTP-ն, ոչ թե SSH-ը։
- nginx limit_req / limit_conn
Ներկառուցված rate limiting ըստ IP-ի․ կանխում է չարաշահումը տվյալ պահին՝ փաստից հետո ban անելու փոխարեն։
Լավագույն պրակտիկաներ
- Բոլոր կարգավորումները դիր jail.local-ում կամ jail.d/*.local-ում․ երբեք մի խմբագրիր jail.conf-ը։
- Խիստ jail-երը միացնելուց առաջ քո static IP-ները ավելացրու ignoreip-ում։
- Յուրաքանչյուր custom filter ստուգիր fail2ban-regex-ով իրական log-երի վրա։
- Համառ հարձակվողների համար միացրու bantime.increment-ը և recidive jail-ը։
- Cloudflare-ի կամ load balancer-ի հետևում կարգավորիր client-ների իրական IP-ները և այնտեղ արգելափակիր edge-ում։
- Պահպանիր միայն key-երով SSH-ը և default-deny firewall-ը․ fail2ban-ը լրացնում է դրանք, չի փոխարինում։
Տարածված սխալներ
- Ինքդ քեզ արգելափակել՝ սխալ գաղտնաբառեր ստուգելով քո միակ միացումից՝ առանց ignoreip գրառման։
- Օգտագործել գոյություն չունեցող log path (auth.log միայն journal-ով համակարգերում), ուստի jail-ը լուռ ոչինչ չի անում։
- Ban անել CDN-ի կամ load balancer-ի IP-ն, որովհետև nginx-ը log է անում proxy-ի հասցեն։
- Հավատալ, որ fail2ban-ը կանգնեցնում է բաշխված հարձակումները կամ պաշտպանում է հավելվածի խոցելիություններից։
Խորը վերլուծություն
07Engine-ի ներսում. backend-ներ, ամսաթվեր և ban database
Յուրաքանչյուր jail ունի backend, որը մատակարարում է log-ի նոր տողերը։ systemd-ն ուղիղ կարդում է journal-ը և ֆիլտրում ըստ unit-ի, ինչը ժամանակակից Ubuntu-ին պետք է SSH-ի համար։ Պարզ ֆայլերի համար auto-ն փորձում է pyinotify և հետ է ընկնում polling-ի։ Յուրաքանչյուր տող պետք է պարունակի timestamp, որը fail2ban-ը ճանաչում է. այն օգտագործում է log-ի ժամանակը, ոչ թե տողը կարդալու ժամանակը, որոշելու համար, թե արդյոք ձախողումն ընկնում է findtime-ի մեջ։ Սխալ datepattern-ը կամ timezone-ի անհամապատասխանությունը ձախողումները հին են ցույց տալիս, և jail-ը լուռ երբեք չի ban անում։ Ban-երը պահվում են SQLite database-ում՝ /var/lib/fail2ban/fail2ban.sqlite3, ուստի վերականգնվում են restart-ից կամ reboot-ից հետո։ dbpurgeage-ը, լռելյայն մեկ օր, որոշում է, թե որքան ժամանակ է պահվում ban-երի պատմությունը։ Սա կարևոր է recidive-ի և incremental ban-երի համար. եթե ձեր recidive findtime-ը մեկ շաբաթ է, իսկ պատմությունը մաքրվում է մեկ օրից, կրկնվող խախտողները երբեք չեն ճանաչվում։ fail2ban.local-ում dbpurgeage-ը բարձրացրեք ձեր ամենաերկար findtime-ից ավելի։
# /etc/fail2ban/fail2ban.local
[Definition]
dbpurgeage = 8d # must be longer than recidive findtime
# Check which date format and lines a filter matches
sudo fail2ban-regex systemd-journal sshd
sudo fail2ban-regex --print-all-missed /var/log/nginx/access.log nginx-probe
08Incremental ban-եր. կրկնվող խախտողների պատժում
Ֆիքսված մեկժամյա ban-ը bot-ին սովորեցնում է վերադառնալ վաթսունմեկ րոպեից։ bantime.increment-ով fail2ban-ը ստուգում է, թե որքան հաճախ է հասցեն նախկինում ban արվել, և բազմապատկում է ban-ը։ Լռելյայն բանաձևն այն ամեն անգամ կրկնապատկում է (ban time-ը բազմապատկած երկուսի ban count աստիճանով), ուստի 1h-ը դառնում է 2h, 4h, 8h և այլն. bantime.multipliers-ը թույլ է տալիս փոխարենը տալ բացահայտ հաջորդականություն։ bantime.maxtime-ը սահմանափակում է աճը, որպեսզի սխալը իրական օգտատիրոջը ամիսներով դուրս չթողնի, իսկ bantime.rndtime-ը ավելացնում է պատահական հավելում, որպեսզի bot-երը չկարողանան ճշգրիտ հաշվարկել unban-ի պահը։ bantime.overalljails = true-ն հաշվում է նախորդ ban-երը բոլոր jail-երից, ոչ միայն ընթացիկից. հասցեն, որը երեկ ստուգում էր nginx-ը, այսօր ստանում է ավելի երկար SSH ban։ Մշտական պատմության հետ միասին սա հաճախ առանձին recidive jail-ը դարձնում է ավելորդ, թեև երկուսն էլ պահելը վնաս չունի։
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
bantime.increment = true
bantime.factor = 1
bantime.maxtime = 1w
bantime.rndtime = 10m
bantime.overalljails = true
# alternative to the formula:
# bantime.multipliers = 1 2 4 8 16 32 64
09Action-ներ մասշտաբում. nftables set-եր, IPv6 և edge
Հին iptables action-ները յուրաքանչյուր ban արված հասցեի համար ավելացնում էին մեկ կանոն, և յուրաքանչյուր փաթեթ անցնում էր այդ ցուցակով, ինչը հազարավոր ban-երի դեպքում դանդաղում է։ Debian-ի և Ubuntu-ի օգտագործած nftables action-ները հասցեները դնում են set-ի մեջ inet f2b-table-ի ներսում, ինչը hash lookup է՝ անկախ չափից, և մեկ աղյուսակում ընդգրկում է IPv4-ը և IPv6-ը։ allports տարբերակը արգելափակում է բոլոր port-երը, ինչն օգտակար է recidive-ի համար, իսկ multiport-ը արգելափակում է միայն jail-ի port-երը։ IPv6-ը մտածել է պահանջում. fail2ban-ը ban է անում առանձին հասցեներ, բայց մեկ հարձակվողը կարող է վերահսկել ամբողջ /64 և պարզապես փոխել հասցեները։ Սա ևս մեկ պատճառ է, որ իրական պաշտպանությունը մնան rate limit-ները և միայն key-երով SSH-ը։ Cloudflare-ի հետևում HTTP-ի համար cloudflare-token action-ը Cloudflare API-ի միջոցով scope արված token-ով ստեղծում է zone access rule, ուստի արգելափակումը տեղի է ունենում edge-ում, որտեղ տրաֆիկն իրականում հասնում է։ Համատեղեք այն լոկալ action-ի հետ, որպեսզի SSH-ը և ուղիղ origin-ին ուղղված հարցումները դեռ արգելափակվեն սերվերում։
# See the nftables sets fail2ban maintains
sudo nft list table inet f2b-table
# jail.d/nginx-probe.local: block locally and at Cloudflare
[nginx-probe]
action = %(action_)s
cloudflare-token[cfzone="your_zone_id", cftoken="your_scoped_token"]
10Ֆիլտրեր, որոնք հնարավոր չէ չարաշահել
Ֆիլտրը չվստահված տեքստը վերածում է firewall կանոնների, ուստի այն անվտանգության սահման է։ Log-երը հաճախ պարունակում են հարձակվողի վերահսկած դաշտեր. username, URL, User-Agent։ Եթե regex-ը anchor արված չէ, հարձակվողը կարող է զոհի IP հասցեն դնել այդպիսի դաշտի մեջ և ստիպել ձեզ ban անել այդ զոհին, օրինակ՝ ձեր payment provider-ին կամ մոնիթորինգի ծառայությանը։ Log injection-ի այս ռիսկի պատճառով է, որ առաքվող ֆիլտրերը anchor են արվում տողի ֆիքսված կառուցվածքի վրա և <HOST>-ը capture են անում միայն այնտեղ, որտեղ ծառայությունն ինքն է գրում client-ի հասցեն։ Custom ֆիլտրերի կանոններ. anchor արեք ^-ով և համընկեք log-ի ճշգրիտ ձևաչափին, host-ը capture արեք այն դաշտից, որը վերահսկում է ձեր սերվերը, pattern-ը պահեք կոնկրետ մեկ ձախողման իմաստի համար և խուսափեք nested greedy wildcard-ներից, որոնք դանդաղ են երկար տողերում։ Հայտնի լավ տրաֆիկի, օրինակ՝ health check-երի համար օգտագործեք ignoreregex։ Միացնելուց առաջ թեստավորեք fail2ban-regex-ով մեկ շաբաթվա իրական log-երի վրա և նայեք և՛ համընկած, և՛ բաց թողնված տողերին։
Իրական իրավիճակներ
Գործընկերը արգելափակվել է demo-ից առաջ
Խնդիր
Developer-ի նոր deploy script-ը գրասենյակի կապից անընդհատ կրկնում էր SSH-ը սխալ user name-ով։ Հիմա նրա կապը timeout է լինում, իսկ demo-ն սկսվում է տասը րոպեից։
Ինչպես լուծել
Մեկ այլ session-ից հաստատեք պատճառը sudo fail2ban-client banned-ով և /var/log/fail2ban.log-ում grep արեք նրա հասցեն՝ տեսնելու, թե որ jail-ն է այն ban արել։ Հեռացրեք ban-ը sudo fail2ban-client set sshd unbanip 203.0.113.10-ով, կամ unban-ով՝ բոլոր jail-երից մաքրելու համար։ Եթե incremental ban-երը միացված են, պատմությունը դեռ հաշվվում է, ուստի հայտնի ստատիկ գրասենյակային կամ VPN հասցեի համար ավելացրեք այն jail.local-ի ignoreip-ում և reload արեք։ Հետո ուղղեք արմատական պատճառը. script-ում ուղղեք user-ը և դադարեցրեք կույր retry-ները։ Եթե թիմն աշխատում է տնից՝ փոփոխվող IP-ներով, ֆիքսված exit հասցեով VPN-ը ավելի մաքուր է, քան ignoreip-ը լայնացնելը։
sshd jail-ը նոր սերվերում ցույց է տալիս զրո ձախողում
Խնդիր
journalctl-ում auth log-ը լի է «Invalid user» փորձերով, բայց մեկ օր անց fail2ban-client status sshd-ն հաղորդում է զրո failed և զրո banned։
Ինչպես լուծել
Jail-ը կարդում է սխալ աղբյուր։ Ubuntu 24.04-ում և ավելի նորերում SSH log-երը գնում են journal, իսկ /var/log/auth.log-ը կարող է բացակայել կամ թերի լինել, ուստի ֆայլային logpath-ով jail-ը երբեք ոչինչ չի տեսնում։ jail.local-ում sshd-ի համար սահմանեք backend = systemd, reload արեք fail2ban-client reload-ով և fail2ban-client status sshd-ով հաստատեք, որ journal-ի համընկնումները հայտնվում են։ Ֆիլտրն ուղիղ թեստավորեք fail2ban-regex systemd-journal sshd-ով։ Ստուգեք նաև, որ sshd ֆիլտրի mode-ը համապատասխանում է ձեր log-ի մանրամասնությանը, և որ սերվերի ժամացույցը և timezone-ը ճիշտ են, քանի որ findtime-ից դուրս timestamp ունեցող ձախողումներն անտեսվում են։
xmlrpc.php-ն հեղեղում է Cloudflare-ի հետևում գտնվող կայքը
Խնդիր
Cloudflare-ի հետևում գտնվող WordPress կայքը ռմբակոծվում է xmlrpc.php-ին ուղղված POST հարցումներով։ fail2ban-ը ban-եր է հաղորդում, բայց հարցումները շարունակում են գալ, և PHP-FPM-ը հագեցած է։
Ինչպես լուծել
Ban-երը ոչ մեկին օգտակար չեն հարվածում։ Կամ nginx-ը log է անում Cloudflare-ի հասցեները, և դուք ban եք անում Cloudflare-ին, կամ իրական IP-ն log է արվում, բայց տրաֆիկը դեռ գալիս է Cloudflare-ի ցանցից։ Նախ կարգավորեք realip մոդուլը Cloudflare-ի range-երով և CF-Connecting-IP-ով։ Հետո jail-ին ավելացրեք cloudflare-token action-ը, որպեսզի խախտողները արգելափակվեն edge-ում։ Այս դեպքի համար ավելի լավ է. եթե xmlrpc.php-ն պետք չէ, արգելեք այն nginx-ում location = /xmlrpc.php { deny all; }-ով և ավելացրեք Cloudflare WAF rule, որն արգելափակում է այդ path-ը, որպեսզի հարցումները երբեք չհասնեն PHP-ին։ fail2ban-ը մնում է այն ամենի համար, ինչը կսողոսկի։
Արագ ուղեցույց
- Ստուգել կոնֆիգուրացիան
sudo fail2ban-client -t- Արտածել գործող կոնֆիգուրացիան
sudo fail2ban-client -d | less- Ցույց տալ jail-ի ընթացիկ կարգավորումները
sudo fail2ban-client get sshd bantime && sudo fail2ban-client get sshd maxretry- Ձեռքով ban անել հասցեն
sudo fail2ban-client set sshd banip 203.0.113.10- Թեստավորել ֆիլտրը journal-ի վրա
sudo fail2ban-regex systemd-journal sshd- Ցույց տալ ֆիլտրի բաց թողած տողերը
sudo fail2ban-regex --print-all-missed /var/log/nginx/access.log nginx-probe- Ուսումնասիրել nftables set-երը
sudo nft list table inet f2b-table- Պահել ban-երի պատմությունը մեկ շաբաթ
[Definition] dbpurgeage = 8d # in fail2ban.local- Հաշվել այսօրվա ban-երը
sudo grep "$(date +%F)" /var/log/fail2ban.log | grep -c ' Ban '
Իմ իրական նախագծերում
- fail2ban-ը և ufw-ն աշխատում են իմ կառավարած production սերվերների վրա։
- Իմ baseline-ը fail2ban-ը զուգակցում է unattended-upgrades-ի, միայն key-երով SSH-ի և firewall-ի հետ, որը բացում է միայն 22, 80 և 443։
- Cloudflare-ի հետևում գտնվող կայքերում edge-ը հոգում է DNS-ը և հիմնական DDoS պաշտպանությունը, իսկ fail2ban-ը ծածկում է այն, ինչ հասնում է սերվերին։
Հարցեր և պատասխաններ
Q1Ի՞նչ է fail2ban-ը, և ինչպե՞ս է այն աշխատում։
fail2ban-ը log-based intrusion prevention daemon է։ Այն հետևում է log ֆայլերին կամ systemd journal-ին, կիրառում է filter-ներ, որոնք regular expression-ներ են, որոնք հայտնաբերում են ձախողումները և հանում client-ի IP-ն, և հաշվում է ձախողումները ըստ IP-ի։ Երբ IP-ն findtime-ի ընթացքում հասնում է maxretry ձախողման, jail-ը գործարկում է իր action-ը, սովորաբար ավելացնելով firewall կանոն nftables-ի, iptables-ի կամ ufw-ի միջոցով bantime-ի տևողությամբ։ Հետո այն ավտոմատ unban է անում։ Jail-երը միավորում են log-ի աղբյուրը, filter-ը, action-ը և շեմերը, ուստի նույն մեխանիզմը պաշտպանում է SSH-ը, nginx basic auth-ը, mail սերվերները կամ քո սեփական հավելվածը, քանի դեռ այն ձախողումները log է անում աղբյուրի հասցեով։
Q2Եթե SSH-ն արդեն օգտագործում է միայն key-եր, ինչո՞ւ ընդհանրապես գործարկել fail2ban։
Միայն key-երի դեպքում գաղտնաբառի brute force-ը չի կարող հաջողել, ուստի fail2ban-ն այլևս չի պաշտպանում հենց login-ը։ Այն դեռ արժեք է ավելացնում․ նվազեցնում է log-ի աղմուկը, որպեսզի իրական իրադարձությունները աչքի ընկնեն, խնայում է մի քիչ CPU և bandwidth, որոնք ծախսվում են անվերջ handshake-ների վրա, դանդաղեցնում է scanner-ներին, որոնք փնտրում են թույլ ծառայություններ կամ սխալ կոնֆիգուրացիաներ, և պաշտպանում է այլ ծառայություններ, ինչպես վեբ login-ները և admin տարածքները։ Այն նաև safety net է տալիս, եթե ինչ-որ մեկը ժամանակավորապես նորից միացնի գաղտնաբառերը։ Բայց ես երբեք չէի հենվի դրա վրա միայն key-երով SSH-ի, default-deny firewall-ի և թարմացումների փոխարեն։ Այն էժան լրացուցիչ շերտ է, ոչ թե հիմք։
Q3Ի՞նչ են bantime-ը, findtime-ը և maxretry-ն։
Դրանք jail-ի շեմերն են։ maxretry-ն ձախողումների քանակն է, որը trigger է անում ban։ findtime-ը սահող պատուհանն է, որի ընթացքում այդ ձախողումները պետք է տեղի ունենան․ մեկ շաբաթվա ընթացքում հինգ ձախողումը չի հաշվվի, եթե findtime-ը տասը րոպե է։ bantime-ը այն է, թե որքան ժամանակ է IP-ն մնում արգելափակված․ բացասական արժեքը նշանակում է մշտական։ Տիպիկ սկզբնական արժեքներն են տասը րոպեում հինգ ձախողում մեկ ժամվա ban-ի համար, SSH-ի համար ավելի խիստ։ bantime.increment-ը միացված լինելու դեպքում յուրաքանչյուր կրկնվող ban ավելի երկար է տևում, իսկ recidive jail-ը օրերով ban է անում այն IP-ները, որոնք կրկնվող ban են ստանում։ Չափազանց խիստ արժեքները արգելափակում են իրական օգտատերերին, չափազանց թույլերը բաց են թողնում դանդաղ հարձակվողներին։
Q4Մեր կայքը Cloudflare-ի հետևում է։ fail2ban-ը դեռ օգնո՞ւմ է։
Միայն լրացուցիչ կոնֆիգուրացիայով։ Proxying-ը միացված լինելու դեպքում յուրաքանչյուր HTTP միացում քո սերվերին հասնում է Cloudflare-ի հասցեներից, ուստի nginx-ը log է անում Cloudflare-ի IP-ներ, եթե չկարգավորես real_ip մոդուլը Cloudflare-ի միջակայքերով և CF-Connecting-IP header-ով։ Նույնիսկ այդ դեպքում սերվերի firewall-ի ban-ը արգելափակում է հարձակվողի IP-ն, բայց նրա request-ները դեռ գալիս են Cloudflare-ից, ուստի ban-ը ոչ մի ազդեցություն չունի։ Քեզ պետք է action, որը Cloudflare-ում ստեղծում է block կանոն նրա API-ի միջոցով, կամ ավելի լավ՝ ուղիղ օգտագործիր Cloudflare-ի WAF-ը և rate limiting-ը։ SSH-ի համար, որը Cloudflare-ով չի անցնում, fail2ban-ը աշխատում է նորմալ։ Ես նաև 80 և 443 port-երը սահմանափակում եմ Cloudflare-ի IP միջակայքերով։
Q5Ինչպե՞ս կհամեմատես fail2ban-ը և CrowdSec-ը։
Երկուսն էլ կարդում են log-եր և ban են անում վատ վարքով IP-ներ։ fail2ban-ը մեկ, հասուն daemon է՝ պարզ, offline, հեշտ հասկանալի, կարգավորվում է regex filter-ներով և action-ներով։ CrowdSec-ը առանձնացնում է հայտնաբերումը, որն անում է իր agent-ը parser-ներով և scenario-ներով, remediation-ից, որն անում են bouncer-ները firewall-ի, nginx-ի, Cloudflare-ի և այլոց համար, ուստի մեկ հայտնաբերման engine կարող է սնել մի քանի կիրառման կետ։ Դրա հիմնական առավելությունը համայնքի ընդհանուր blocklist-ն է․ այլ օգտատերերի հաղորդած IP-ները կարող են արգելափակվել, մինչև դիպչեն քո սերվերին։ Գինը ավելի շատ բաղադրիչներն են, online console-ը և ավելի շատ սովորելու բան։ Մեկ կամ երկու փոքր սերվերի համար fail2ban-ը բավական է, սերվերների մեծ պարկի համար CrowdSec-ը ավելի լավ է scale լինում։
Սենիոր մակարդակի հարցեր
S1Դուք ունեք տասնհինգ սերվեր։ Ինչպե՞ս եք կազմակերպում brute-force պաշտպանությունը ամբողջ fleet-ում։
Յուրաքանչյուր սերվերի fail2ban-ն աշխատում է, բայց յուրաքանչյուր սերվեր սովորում է միայնակ. մեկում ban արված հասցեն մյուս տասնչորսում թարմ է։ Տարբերակներ՝ ըստ ջանքի. Ansible-ով deploy արեք նույնական fail2ban կոնֆիգուրացիա, որպեսզի գոնե վարքագիծը հետևողական լինի, ավելացրեք action, որը ban-երը ուղարկում է ընդհանուր blocklist, օրինակ՝ cloud provider-ի firewall կամ Cloudflare, որպեսզի մեկ հայտնաբերումը պաշտպանի բոլորին, կամ անցեք CrowdSec-ի, որի local API-ն թույլ է տալիս մի քանի agent-ների կիսել որոշումները, իսկ bouncer-ները դրանք կիրառում են firewall-ների, nginx-ի և CDN-ի վրա։ Ավելի մեծ շահը ճարտարապետական է. SSH-ը դրեք VPN-ի կամ bastion-ի հետևում, որպեսզի միայն մեկ host բաց լինի, և թողեք, որ HTTP-ն կառավարի edge-ը։ Այդ դեպքում brute-force պաշտպանությունը երկու կոմպոնենտի խնդիր է, ոչ թե տասնհինգի։
S2Որո՞նք են fail2ban-ն ինքնին աշխատեցնելու ռիսկերը։
Այն աշխատում է որպես root և log-ի բովանդակությունը վերածում firewall կանոնների, ուստի մի փոքր լայնացնում է ձեր attack surface-ը։ Հիմնական ռիսկը log injection-ն է. վատ anchor արված custom ֆիլտրը թույլ է տալիս հարձակվողին զոհի հասցեն գրել username-ի կամ URL-ի մեջ և ban անել նրան, ինչը կարող է արգելափակել ձեր payment provider-ին, մոնիթորինգը կամ գրասենյակը։ Երկրորդը՝ հասանելիությունը. չափազանց ագրեսիվ jail-երը ban են անում իրական հաճախորդներին ընդհանուր carrier-grade NAT-ի հետևում, որտեղ հազարավոր օգտատերեր կիսում են մեկ IPv4 հասցե։ Երրորդը՝ կեղծ վստահությունը. լուռ ոչինչ չհամընկնող jail-ը պաշտպանության տեսք ունի։ Ռիսկերը նվազեցնում եմ fail2ban-regex-ով թեստավորված anchor արված ֆիլտրերով, կրիտիկական գործընկերների համար ignoreip-ով, հրապարակային web jail-երում չափավոր շեմերով և alert-ներով, երբ սովորաբար ban անող jail-ը լռում է։
S3Rate limiting nginx-ում, թե՞ ban fail2ban-ով. որն եք օգտագործում login endpoint-ի համար։
Երկուսն էլ, քանի որ դրանք տարբեր աշխատանք են անում։ limit_req-ը գործում է իրական ժամանակում յուրաքանչյուր հարցման վրա. այն սահմանափակում է, թե որքան արագ կարող է ցանկացած հասցե գաղտնաբառեր փորձել, պաշտպանում է հավելվածը գերբեռնվածությունից և անմիջապես վերադարձնում 429՝ առանց log-երին սպասելու։ Այն արագ է մոռանում, ուստի դանդաղ հարձակվողը կարող է շարունակել անվերջ։ fail2ban-ը գործում է փաստից հետո՝ րոպեների կամ օրերի ընթացքում կուտակված ապացույցների հիման վրա, և հարձակվողին ամբողջությամբ հեռացնում է firewall-ում՝ խնայելով TLS handshake-ները և հավելվածի աշխատանքը։ Հավելվածը նույնպես պետք է ավելացնի իր կառավարման միջոցները. per-account throttling, քանի որ հարձակվողները փոխում են IP-ները, բայց թիրախավորում նույն account-ները, գումարած multi-factor authentication։ Հերթականությունը defence in depth է. edge WAF, nginx rate limit, app throttling, հետո fail2ban՝ համառ աղբյուրները ban անելու համար։
Բառարան
- Jail
- fail2ban-ի միավոր, որը մեկ ծառայության համար համատեղում է log-ի աղբյուրը, ֆիլտրը, action-ը և շեմերը։
- Filter
- Regular expression-ների հավաքածու, որը log-ում ճանաչում է ձախողման տողերը և դուրս բերում խախտողի հասցեն։
- Action
- Այն, ինչ fail2ban-ն աշխատեցնում է ban-ի և unban-ի ժամանակ, օրինակ՝ հասցեն ավելացնում է nftables set-ում կամ կանչում API։
- failregex
- Ֆիլտրի regular expression-ը, որը log-ի տողը նշում է որպես ձախողում. այն պետք է capture անի <HOST>։
- <HOST>
- fail2ban-ի placeholder-ը failregex-ի ներսում, որը համընկնում և capture է անում IP հասցե կամ hostname։
- Backend
- Ինչպես է jail-ը ստանում log-ի տողերը. systemd journal-ից, inotify-ով ֆայլերին հետևելով կամ պարբերական polling-ով։
- Recidive
- Jail, որը հետևում է fail2ban-ի սեփական log-ին և շատ ավելի երկար ban է անում այն հասցեները, որոնք անընդհատ ban են ստանում։
- ignoreip
- Հասցեներ կամ ցանցեր, որոնք երբեք ban չեն արվում, օրինակ՝ ձեր գրասենյակը, VPN-ը կամ մոնիթորինգի ծառայությունը։
- Log injection
- Log parser-ի խաբում՝ հարձակվողի վերահսկած դաշտերում հատուկ տեքստ, օրինակ՝ զոհի IP-ն տեղադրելով։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։