WordPress е най-популярната система за управляване на съдържанието (CMS - Content Management System) в световен мащаб. Според данните в момента на нея се движат около 1/4 от всички сайтове. Знаете, че когато една система стане малко по-популярна, веднага се намират “доброжелатели”, целящи да използват слабостите ѝ в неин ущърб. Преди няколко години в интернет се появиха атаки към WordPress сайтове, целящи познаване на потребителските пароли. Ако за потребителите не е проблем да се намерят техните имена, то паролите са изключително проблемни.
Вграденият генератор на пароли всъщност генерира много силни пароли - цифри, символи, главни и малки букви. Прoблемът обаче е, че потребителите не могат да ги запомнят. Затова те ги заменят с нещо лесно и просто, което могат да запомнят. Така хубавата и сложна парола “S57P4O-3[w” се превръща във qwerty, 123456, 12345678, testtest, 1qaz2wsx или просто password. В такива случаи разпознаването на паролите се превръща в детска игра. Само трябва да бъдат намерени списъци с лесни пароли от интернет и се започва “бомбене” на нечий WordPress. Процесът на разпознаването натоварва сървъра, WordPress хостинга и използва повече процесорни ресурси, затова сега ще ви демонстрираме с няколко прости стъпки как да защитите вашия WordPress.
Съществуват 3 начина за вход в WordPress:
- wp-login.php - това е единственият официален начин за вход в административния панел на системата
- xmlrpc.php - това е интерфейс за публикуване, редактиране или изтриване на статии, коментари, категории и тагове
- REST API - това е новият програмен интерфейс за комуникация със системата. Позволява всичко, което XMLRPC поддържа и тепърва ще бъде развиван.
Най-болезнената точка за пробив е wp-login.php и затова започваме с него.
1. Поставяне на HTTP парола за достъп до wp-login.php
Най-лесният и бърз начин за спиране на нежеланите атаки е, когато просто се прибави HTTP парола пред съответния файл. За съжаление cPanel не поддържа тази възможност и ще се наложи да го направите на ръка за Apache:
1.1. Създавате празен файл .htpasswd в основната папка на акаунта, извън public_html
1.2. С помощта на htpasswd generator си генерирате комбинация потребител/парола. Ако имате достъп до *nix можете да отворите команден промпт и да напишете команда, като:
htpasswd -n -b delta hosting
резултатът ще е нещо като това:
delta:$apr1$0ETICz4b$adoy6uvNUr3gsOL30evmb0
1.3. Копираме горния ред потребител:парола, както е във файла .htpasswd
1.4. Прибавяме към .htaccess следните редове
<FilesMatch "wp-login.php">
AuthType Basic
AuthName "Admin Area"
AuthUserFile “/home/път/към/.htpasswd/файла/.htpasswd”
require valid-user</FilesMatch>
Необходимо е да промените пътя към правилното място на файла в директорната структура. И това е всичко за Apache.
За nginx алгоритъмът е следният:
1.1., 1.2., 1.3. по същия начин, както за Apache, но:
1.4. В конфигурацията на nginx добавяме следните редове:
location /wp-login.php {
auth_basic "Administrator Login";
auth_basic_user_file ./път/към/htpasswd/файла/.htpasswd;
}
Важно! Ако има проблем при добавянето на парола, сървърът ще върне грешка 500. Ако я видите, проверете във файла за грешки на уеб сървъра и какво ги предизвиква. Възможно е файлът с паролите да не може да бъде открит, възможно е да няма достъп до него или нещо подобно. Отстранете грешката и се опитайте да достъпите wp-login.php. Ако всичко е наред, ще ви поиска парола. Ако не - нещо сте объркали в конфигурационните файлове.
Само с тази промяна ще спрете всички опити за вход във вашия WordPress. Атакуващите няма да знаят комбинацията от потребител/парола, за да го достъпят. Техниката е отлична за защита на малки сайтове, където броят на авторите е ограничен (един или повече). Този механизъм обаче е несъвместим, и дори вреден, ако се налага потребителите да се регистрират във вашия сайт. Един от най-простите примери е WooCommerce - там потребителите си правят акаунт в системата и горният код ще им попречи.
2. Ограничаване на достъпа до wp-login.php от адрес
Ако се налага сайтът да се достъпи от няколко точки на света и им знаем IP адресите, можем да ограничим достъпа до горния файл само и единствено от тях. Например: Ако едното IP е 1.2.3.4, а другото е 2.3.4.5 се прави следното за Apache:
<Files wp-login.php>
order deny,allow
Deny from all
# whitelist office Sofia IP address
allow from 1.2.3.4
#whitelist office Plovdiv IP Address
allow from 2.3.4.5
</Files>
Така можем да достъпим сайта само и единствено от горните 2 IP-та. Това обаче е проблем, ако адресите са динамични. Тогава може да се използват два други метода.
Първият начин е да дефинираме частичен адрес: “Allow from 1.2.3” тогава ще бъде разрешен достъпа от IP 1.2.3.1 до 1.2.3.254.
Вторият начин е да използваме мрежова маска: “Allow from 1.2.3.0/255.255.255.224” или “Allow from 1.2.3.0/27”
Тогава достъпът ще бъде разрешен за IP-та от 1.2.3.1 до 1.2.3.31 включително. Под nginx горният трик се прави по следния начин:
location /wp-login.php {
allow 1.2.3.4;
allow 2.3.4.5;
deny all;
}
Ако адресите са динамични, можем да прибавим адреси с мрежова маска, като “allow 1.2.3.0/27” и ще разрешим достъпа от 1.2.3.1 до 1.2.3.31 включително.
Тук важи същото, което описахме по-горе. Механизмът работи безотказно, но ако използвате WooCommerce, няма да може да го приложите.
3. Поставяне на плъгин за контрол до wp-login.php
Както горе описахме, използването на решения за електронна търговия прави горните подходи неизползваеми. Затова се налага да се използва модул за WordPress, който да реши проблема. Има много модули, но ние ще ви препоръчаме два, които са се доказали в практиката:
WP Limit Login Attempts
Uber reCaptcha
Първият модул ограничава достъпа по IP адрес. Ако от един адрес дойдат над определен брой заявки, може адресът да се блокира за период от време. Ако няколко пъти един адрес се блокира, наказанието му се удължава с нов и по-голям период. Настройките, които ние препоръчваме, са 5 опита и забрана за час, и при 3 забрани - забрана за ден.
Вторият модул е малко по-сложен и комплексен, защото се използва системата reCaptcha на Google. За два-три опита се минава системата само с натискането на един бутон. При повече опити обаче се показват картинки и въпроси “Избери снимките с река”, “Избери снимките с океан” или нещо подобно. Системата в този си вид е нормална по трудност за потребителите, но невъзможна за преминаване от роботизиран софтуер.
Разбира се има още поне 100 модула за WordPress, които правят защити под една или друга форма. Можете да откриете още много от директорията с модули тук.
4. Ограничаване на достъпа до wp-login.php на база на скорост
Ако горните механизми работят добре на споделен хостинг, на наети сървъри или на виртуални сървъри, има още няколко механизма, които можете да използвате. Първият е ограничение по скорост. По пътя на логиката - от едно IP можете да направите една заявка за секунда и това е нормално. Но ако получите 10 заявки в рамките на 1 секунда към wp-login.php, може да предположите, че имате автоматизирана атака и да я ограничите. Как се прави това под Apache? Един от най-лесните начини е да използвате mod_security и да го конфигурирате по следния начин:
SecRuleEngine On
<LocationMatch “^/wp-login.php”>
SecAction initcol:ip=%{REMOTE_ADDR},pass,nolog
SecAction "phase:5,deprecatevar:ip.somepathcounter=1/1,pass,nolog"
SecRule IP:SOMEPATHCOUNTER "@gt 60" "phase:2,pause:300,deny,status:509,setenv:RATELIMITED,skip:1,nolog"
SecAction "phase:2,pass,setvar:ip.somepathcounter=+1,nolog"
Header always set Retry-After "10" env=RATELIMITED
</LocationMatch>ErrorDocument 509 "Rate Limit Exceeded”
Горните настройки може да се дешифрират така. Ако имате от 1 адрес 1 заявка за 1 секунда е ОК, но ги броите. Ако горният брояч мине 60, тогава забавяте отговора със 300 милисекунди и връщате грешка 509. По този начин разрешавате 60 бързи заявки, след което ги забавяте изкуствено.Можете да промените стойностите според вашите нужди, разбира се. Това са примерни параметри. Друг начин за Apache е да се използва mod_evasive и следната конфигурация:
<IfModule mod_evasive20.c>
DOSHashTableSize 4096
DOSEmailNotify admin@delta.bg
DOSPageInterval 1
DOSPageCount 2
DOSSiteInterval 1
DOSSiteCount 50
DOSBlockingPeriod 60
</IfModule>
Тук имаме таблица от 4096 елемента. Разрешавате на един адрес за една секунда да достъпва 2 пъти една страница. Разрешавате на един адрес за една секунда да достъпи 50 различни страници. Ако ограниченията се преминат, забраняваме достъпа до сайта за 60 секунди с грешка 403 и пращате имейл до администратора. Под nginx защитата може да се организира по следния начин:
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
…
server {
…
location = /wp-login.php {
limit_req zone=one burst=1 nodelay;
}
…
}
}
Тук правите файл от 10 мегабайта, който може да съдържа около 16000 уникални адреси. И ги ограничавате до една заявка за секунда. Правите отделно правило за wp-login.php, където ги ограничавате. При достигане на лимита, се връща грешка 503. Ограничения - не може да се използват дробни числа за ограничения. Ако се налага, трябва да се смени мащабния множител например с rate=30r/m, което е 30 заявки за една минута или грубо 2 заявки за секунда. Второто ограничение е, че ако таблицата се запълни, се връща грешка 503 към всички последвали заявки. Ако се налага да се изключи забраната за специфични адреси, се използва следният механизъм:
map $remote_addr $rt_filtered_ip {
default $binary_remote_addr;
1.2.3.4 "";
2.3.4.5 "";
}
и тогава първият ред се променя на:
limit_req_zone $rt_filtered_ip zone=one:10m rate=1r/s;
Ако се налага отблокиране на мрежа от адреси, нещата стават по-сложни и ще трябва да се използва geo модулът и е необходимо да се използва така:
geo $rt_filtered_ip {
default $binary_remote_addr;1.2.3.0/24 "";
2.3.0.0/16 "";3.4.5.6 “";
4.5.6.7 “";
}
и първият ред пак се променя на:
limit_req_zone $rt_filtered_ip zone=one:10m rate=1r/s;
Важно - този начин на ограничаване е доста добър, но все пак трябва да се внимава с добрите роботи и малко по-нахалните потребители. Пример за добър робот е Googlebot, Bingbot, Yandexbox и още няколко други. Изпращането на 509, 503 или 403 отговор към тях може да има катастрофален резултат за сайта и неговите класирания. Същото важи и за потребителите - ако те видят някаква грешка на истинския сайт, може никога да не се върнат на него. Затова горните конфигурации са просто примерни и най-вероятно ще се наложи да ги редактирате за вашите нужди.
5. Ограничаване на достъпа до wp-login.php на база неуспехи
Ако горният пример е твърде брутален, то настоящия е доста по-лек. Тук се отчитат само неправомерните действия и ако се мине определена граница, се заключва адресът, от който се правят заявките за определено време. Изисква се инсталиране на приложението fail2ban на сървъра и инсталация на модула WP fail2ban.
5.1. Настройка на филтъра:
$ sudo curl https://plugins.svn.wordpress.org/wp-fail2ban/trunk/filters.d/wordpress-hard.conf > /etc/fail2ban/filter.d/wordpress.conf
5.2. Настройка на блокирането
Създайте файл /etc/fail2ban/jail.d/wordpress.conf със следното съдържание:
[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/auth.log
port = http,https
maxretry = 10
findtime = 3600
bantime = 86400
Тук казваме на fail2ban да проверява за над 10 неуспешни опита за достъп за последния час. Ако се случат - се забранява достъпът до сървъра за цял един ден (24 часа). Защо това е технически по-доброто решение от предходното? Защото само и единствено при неправилно действие ще се блокира адреса. Така вие правите ясно и категорично разграничаване на добрите и лошите потребители. Добрите потребители влизат безпроблемно и не се забранява тяхното IP. На лошите обаче след 10-я опит ще им бъде отказван достъпът.
Втората критична точка за WordPress е XMLRPC интерфейсът. Това е един начин за външни приложения или системи да си взаимодействат с WordPress на ниско ниво. Някои действия обаче изискват валидна комбинация от потребител-парола и точно от това се възползват лошите в интернет. XMLRPC беше наличен от първите версии на WordPress, като имаше възможност да бъде включен или изключен достъпът. От версия 3.5 обаче тази възможност отпадна и интерфейсът е постоянно включен. Разбира се, и по-големите атаки не закъсняха.
6. Забрана на XMLRPC
Най-лесното и най-простото е да се забрани изобщо външният достъп до xmlrpc.php. Не се налага модифициране на WordPress и след обновяване защитата ще продължава да работи. Под Apache това се прави с добавянето на един ред към .htaccess:
Redirect 403 /xmlrpc.php
Ако имате nginx, то горният ред се прави по този начин:
location /xmlrpc.php {
deny all;
}
Въпреки че е лесно и просто, това води до няколко ограничения - не можете повече да използвате JetPack, няма да можете да използвате мобилните приложения на WordPress или други приложения, ползващи горния интерфейс.
7. Поставяне на HTTP парола за достъп до XMLRPC
Ако все пак искате да използвате WordPress мобилните приложения, BlogJet, MarsEdit или Windows Live Writer, то можете лесно да решите проблема, като прибавите допълнителна парола за достъп. Начинът за създаването е същият, както точка 1, но единствено трябва да замените wp-login.php със xmlrpc.php. Така даден потребител, който не знае комбинацията от потребителско име/парола, няма да може да изпълни xmlrpc заявка към сайта.
8. Ограничаване на достъпа до XMLRPC от адрес
Това е още един механизъм за защита, като достъпът до ресурса се разрешава само на определни адреси. Начинът за използване е същият, както в точка 2. Тук обаче ще трябва да се разреши и евентуално достъпа от адресите на Automattic:
192.0.64.0/18
Така ще може да се използват настолните приложения на WordPress за управление на системата, а също и JetPack. JetPack идва допълнително със свой модул за защита, който можете да видите тук.
Горните 3 метода работят на споделен хостинг и позволяват драстично да се намали процесорното време в момент на атака към сайта. Няма универсално решение обаче и ще трябва да приложите най-доброто такова във вашия случай.
9. Ограничаване на достъпа до XMLRPC на база неуспехи
Плъгинът WP fail2ban позволява забрана и за достъп до XMLRPC. Само трябва да се приложи всичко, което сме описали в точка 5. За използването на fail2ban е необходим отделен сървър или виртуален сървър. Този механизъм не може да се активира на споделен хостинг.
Има поне още един начин за забраната на XMLRPC - използването на модул. Това обаче не е много добро решение, защото все пак се позволяват извиквания и на сайта се смята процесорно време. Дори може да се каже, че е частично решение на проблема.
10. Забрана на REST API
Новият интерфейс за достъп до WordPress на ниско ниво REST API е въведен във версия 4.7 и е активиран без възможност за изключване. На този етап на всички инсталации обновени до версия 4.7 е наличнен и горният интерфейс. Засега има два начина за забраната му - използване на модул или забрана на ниво сървър. За забраната с модул важи същото, както и за XMLRPC, а именно - смята се процесорно време. Как лесно можете да забраните този интерфейс под Apache?:
RewriteCond %{REQUEST_METHOD} ^(GET|POST|PUT|PATCH|DELETE) [NC]
RewriteCond %{REQUEST_URI} ^.*wp-json/ [NC]
RewriteRule ^(.*)$ - [F]
Това ще върне на всички адреси грешка 403. Или малко по-драстичният метод:
RewriteRule ^wp-json.*$ 404.html
който ще върне на всички адреси съдържанието на файла 404. Под nginx може да се използва това:
location /wp-json {
deny all;
return 404;
}
Като може да се промени на 403 или да се остави на 404 в зависимост от нуждите ви.
Важно - екипът на WordPress имат големи планове за това REST API и занапред може тази техника да се окаже проблемна за модули, теми или приложения. Да - механизмът сега работи, защото няма такива, които да го ползват, но не можем да предвидим как ще се развият нещата. Когато излезе нещо по-интересно, използващо REST API, си оставяме вратичка, че ще го опишем и ще допълним тази секция с актуална информация. Почти е сигурно, че настолните приложения и мобилните приложения на WordPress до няколко месеца ще започнат да използват и горния интерфейс.
11. Тайната съставка на Делта Хостинг
Всъщност това си е нашата малка тайна за оптимизирането на нашите сървърни ресурси. Нещата всъщност са много прости и са разработени от нашите магьосници с цел оптимизация на сървърите за избягване на претоварването им. Технически - когато започне атака по сървър от нашата мрежа, се забранява достъпът до него. Но ако атаката продължава, има възможност да се забрани изцяло достъпът до всички ресурси на Делта от страна на атакуващия. Ако в атаката са включени и няколко други сървъри от мрежата на атакуващия, има възможност да се забрани и достъпът на цялата им мрежа към нашите ресурси.
Всичко това е направено с цел оптимизация. Ако вие си забравите паролата и направите опит за достъп до WordPress, това е напълно нормално дори и няколко пъти да пробвате това. Но ако това го направите със скорост няколко хиляди опита в рамките на няколко минути, то ние няма как да го сметнем за инцидентно забравяне на паролата. Тогава нашата тайна съставка се задейства и атакуващият бива блокиран. Тъй като е тайна обаче, не можем да разкрием как и кога се сработва и за колко дълго. Ако все пак много искате да я научите, можете да се свържете с наш служител на jobs@delta.bg и да поговорите за бъдещите ви творчески планове и, дори, как можете да подобрите тайната ни съставка.
Както виждате, защитата за WordPress не е никак сложна, но при определни условия не е и никак проста. Реално всичко зависи от вашите нужди. Както изрично споменахме, някои неща не са предназначени изобщо за определени конфигурации, например за Woo, други изискват най-малко виртуален сървър за цялостна настройка.
Хитрото е, че горните кодове, с малки модификации, може да се настроят и за други уеб системи - Joomla, Drupal, Magento, Opencart, Prestashop и много други. Моралната страна на въпроса - трябва ли да ви е жал за временно блокиран адрес или ресурс? Според нас лично - не. Автоматизираните проверки на пароли натоварват сървърната инфраструктура няколко пъти над обичайното ниво. Това може да доведе до забавяне на останалите потребители, забавяне на другите роботи, най-вече на търсачките, забавяне на сървъра, както и до драстично вдигане на ресурса “процесорно време”, който е ахилесовата пета на споделен хостинг.
По-горе използвахме термина “бомбене”. Откъде идва? По време на Втората Световна Война е използван шифърът "Енигма" от нацистите, който съюзниците отчаяно са се опитвали да пробият. За времето си това бил най-сигурният код и е бил абсолютно неподатлив на човешки атаки. Английски екип обаче, начело с Алън Тюринг, създава машина, която да атакува кода. Името на тази машина е Bombe и е първата машина, специално създадена за машинна атака над криптографски код. Терминът “бомбене” идва от процеса на работа на самата машина. И “бомбенето” е било успешно - въпреки сложната криптография, кодът е бил разбит. Настоящите системи за груба проверка на пароли са един съвременен вид на Bombe.
7 коментара
По-детайлна статия от тази за справяне с проблемите на любимия wordpress, няма. :-)
Много е добра. Впрочем харесвам приложението WordFence за WordPress - и то върши добра работа.
Поздравления за полезната статия! По отношение на приложенията ще кажа, че често товарят сървъра и по-добре без приложения ;)
Използвам WP Security и съм доволен от този плъгин, има филтри за блокиране или разрешавана на IP адреси за логин формата и вграден Firewall. за сега върши чудесна работа.
Поздравления Петър, много добра статия, прочетох я, но нещата са много и ще си добавя в архива, за да може да може когато ми се наложи да приложим нещатата в действие
Прекрасна и изчерпателна статия. Браво за написаното и за подробните обяснения.
много детайлен и полезен материал. Браво на Петър.