В предыдущей статье мы рассматривали как удалить следы присутствия Joomla с сайта. Теперь более детально остановимся на следующей популярной платформе для сайтов - Wordpress. По аналогии с Joomla мы попытаемся с минимальными потерями и возможностью дальнейшего обновления сайта.

Затираем признаки Wordpress - удаляем следы присутствия
Затираем признаки Wordpress - удаляем следы присутствия

В первую очередь стоит скрыть доступ посторонним для админки. Похожее мы делали в джумле, однако в случае с вордпрессом есть свои нюансы.

В любом случае защита админки - это жирный плюс к безопасности. Почему? Да очень просто. Очень многие сайты подвергаются атаке брутофорса или перебора паролей, говоря простым языком. Часть из них падет ниц перед злоумышленниками. Кроме этого, многие известные уязвимости плагинов и CMS находят свое применение через административную панель сайта. В том случае, когда уязвимости нулевого дня остаются без доступа к админке, они становятся бесполезными, а сайт остаётся невредимым.

Как удалить следы вордпресса своими руками с сайта

Теперь, когда мы убедились в необходимости усиления панели управления сайтом, займемся этим на практике.

Мы будем делать это стандартными средствами Apache, без использования сторонних плагинов. Существует два варианта запрета доступа: по айпи или по паролю.

Рассмотрим для начала вариант с ip. В этом случае мы должны иметь статический айпи-адрес, на худой конец айпи адреса одних подсетей.

Создадим в папке wp-admin файл .htaccess и добавим директиву deny,allow

order deny,allow
deny from all
allow from xxx.xxx.xxx.xxx

где вместо  xxx.xxx.xxx.xxx мы ставим наш адрес. Через запятую можно указать несколько айпи-адресов или можно указать маску подсети  xxx.xxx.xxx. ( в этом случае будут работать все адреса начинающиеся на данную маску).

Внимание! Если ваша тема или плагины на сайте используют технологию аякс (AJAX), то вполне возможно, что нам придется открыть доступ к одному файлу в папке, для этого необходимо дописать в файл .htaccess следующий код:

<Files admin-ajax.php>
Order allow,deny
Allow from all
Satisfy any
</Files>

После таких манипуляций любой посторонний доступ к папке wp-admin будет запрещен. Если же понадобится зайти с другого компьютера на другом айпи, не забудьте зайти по фтп и добавить нужный адрес в список.

Однако мы не защитили саму авторизацию, если на вашем сайте не используется регистрация и вход пользователей, то в корневой файл .htaccess стоит добавить следующие строки:

<Files wp-login.php>
order deny,allow
deny from all
allow from xxx.xxx.xxx.xxx
</Files>

где опять укажем наш белый айпишник. Данная мера поможет избежать возможности bruteforce на сайт.

Если регистрация и авторизация на сайте не нужны (это актуально для большинства сайтов-визиток), то стоит и закрывать файл xmlrpc.php - через него хакеры любят перебирать пароли через POST запросы. Здесь правда можно вообще закрывать прямой доступ, не обязательно по айпи или basic или digit авторизации.

<Files xmlrpc.php>
order deny,allow
deny from all
allow from xxx.xxx.xxx.xxx
</Files>

Второй метод основан на установке парольной защиты на директорию wp-admin и файл wp-login.php

Код для закрытия wp-login.php

<Files wp-login.php>
AuthName "Protected area, need authorization"
AuthType Basic
AuthUserFile /path/to/file/htpasswd/.htpasswd
Require valid-user
</Files>

Аналогично выглядит и для файла xmlrpc.php

<Files xmlrpc.php>
AuthName "Protected area, need authorization"
AuthType Basic
AuthUserFile /path/to/file/htpasswd/.htpasswd
Require valid-user
</Files>

Не буду повторяться о данном методе, подробно это описано в защите админки джумлы, приведу лишь пример для файла .htaccess в папке wp-admin, где мы исключаем файл admin-ajax.php:

AuthType Basic

AuthName "Welcome home"

AuthUserFile "path to .htpasswd file"

SetEnvIf Request_URI ^/wp-admin/admin-ajax.php.* noauth=1

Order Deny,Allow

Satisfy any

Deny from all

Require valid-user

Allow from env=noauth

Закрываем админку Wordpress на Apache 2.4

В новых версиях апача директивы order, deny и allow были упразднены и заменены на require. Старые правила конечно продолжают работать (неизвестно до какой версии правда), но в логах будут возникать такого рода ошибки:

[access_compat:error] AH01797: client denied by server configuration:

Дабы избежать такого мусора да и проблем с совместимостью будущем перепишем наши правила, настоятельно советую всем, у кого используется Apache 2.4 использовать новые правила!

Итак, запрет по айпи административной панели вордпресс теперь превратится в одну строчку:

Require ip 127.0.0.1

Для исключения из правил аякс запросов добавляем следующие строки:

<Files admin-ajax.php>
Require all granted
</Files>

Точно также будет и для авторизации через wp-login.php:

<Files wp-login.php>
Require ip 1.2.3.4
</Files>

Двухфакторная авторизация для админки примет следующий вид:

AuthType Basic
AuthName "Welcome home"
AuthUserFile /path/to/file/.htpasswd
Require valid-user
<Files admin-ajax.php>
Require all granted
</Files>

А для закрытия авторизации на сайте через wp-login.php или xmlrpc.php ничего не изменится. 

Как видим ничего сложного нету, и новые директивы более просты в использовании.

Удаляем версию Wordpress на сайте

Следующим шагом будет удаление генератора из кода html. Достаточно открыть исходный код любой страницы и можно лицезреть следующее:

<meta name="generator" content="WordPress 4.5.3"/>

Согласитесь, это нам совсем ни к чему. 

Делается это совсем просто, достаточно найти файл functions.php вашей темы ( расположена по пути wp-content/themes/<названиетемы> ) добавить функцию:

remove_action('wp_head', 'wp_generator');

Идем дальше, глянем на файлы в корне. По умолчанию там любят скапливаться разные информационные файлы, которые подлежат немедленному удалению.

Стандартный набор таких файлов: readme.html, license.txt иногда бывают с разрешением .md

В любом случае желательно и в папках шаблонов и плагинов удалить файлы версий как changelog, readme и license с различными видами расширений. Это предотвратит распознавание версий плагинов, а значит и невозможность подбора уязвимости под версию.

С другой стороны, при обновлении сайта эти файлы будет созданы вновь, и удалять каждый раз согласитесь не комильфо. Поэтому можно просто сделать запретить доступ в файле .htaccess к определенным файлам:

<Files readme.html>

Order deny,allow

Deny from all

</Files>

<Files wp-config-sample.php>

Order deny,allow

Deny from all

</Files>

<Files license.txt>

Order deny,allow

Deny from all

</Files>

Расширить список файлов можно и самому, добавив по аналогии свои.

Если мы хотим запретить конкретные типы файлов, к примеру txt,sql и т.д. - можно воспользоваться следующей конструкцией (убедитесь, что не блокируете лишнее как карта сайта или robots.txt):

<Files ~ "[\.(txt|sql|ini|xml)$">

Order allow,deny

Deny from all

Satisfy all

</Files>

Не забываем открыть доступ нужным файлам, особенно ценных для поисковиков:

<Files sitemap.xml>
Order allow,deny
Allow from all

 

</Files>
<Files robots.txt>
Order allow,deny
Allow from all

 

</Files>

Запрещаем обращение к корневым файлам вордпресс

Теперь коснемся файлов внутри корневой директории - это все файлы, начинающиеся на wp- (wp-config.php, wp-cron.php и другие) и файл xmlrpc.php

При прямом запросе к этим файлам мы будем получать различные ответы сервера, отличные от 404 - а значит файл существует. В интернете советуют решение прописать редирект с этих файлов на 404 ошибку. Честно говоря, мне этот метод не особо нравится, я бы лучше запрещал прямой доступ к файлам через директиву deny, allow

Однако даже и в этом случае у нас будет 403 ошибка вместо 404 - но и тут можно решить проблему, достаточно переопределить разного рода ошибки на 404 - и обязательно включить логирование, чтобы просматривать реальные ошибки сервера.

В любом случае, я советую для начала проанализировать работу сайта с закрытым прямым доступом к этим файлам - чересчур торопиться не стоит, при закрытии некоторых файлов можно закрыть доступ к авторизации или регистрации, фиду новостей и другим возможностям - поэтому будьте предельно осторожны с этим пунктом!

Как запрещать доступ к отдельным файлам было показано выше, для любителей краткости могу предложить такой вариант:

<FilesMatch "\.htaccess.*|\.htpasswd.*|xmlrpc\.php|wp\-cron\.php|wp_cron\.php">

order allow,deny

deny from all

</FilesMatch>

Удаляем версии скриптов в коде страницы на сайтах Wordpress

Ну и напоследок, один из явных признаков определения точной версии вордпресс - это версионность скриптов и стилей. Если присмотреться в исходный код html, то можно обнаружить добавки к путям скриптов:

<script type="text/javascript" src="/wp-includes/js/wp-embed.min.js?ver=4.7.2"></script>

В некоторых случаях скрипты имеют свою версию, но большинство получают номер текущей сборки, тем самым выдают реальную версию вордпресса. Для чего воообще это сделали разработчики? Ответ прост, многие браузеры кешируют скрипты и стили на компьютере и при обновлении файлов скриптов не все пользователи могут додуматься обновить кеш. А различия в коде обновления могут исказить сайт в нелучшую сторону. Добавление версии позволяет избавиться от этой проблемы.

Итак, приведу решение, как избавиться раз и навсегда от определения версии Wordpress. Не знаю, кто именно придумал этот метод, но он действенен, необходимо добавить в файл functions.php следующие строки:

function _remove_script_version( $src ){
	$parts = explode( '?', $src );
	return $parts[0];
}
//Это для скриптов
add_filter( 'script_loader_src', '_remove_script_version', 15, 1 );
//Это для стилей
add_filter( 'style_loader_src', '_remove_script_version', 15, 1 );

Заметаем все следы Wordpress полностью

С большей частью работы мы справились, однако признаков определения  CMS остается прилично. Полностью мы не сможем избавиться от всех следов, не нарушив работоспособность, однако попробуем выжать максимум. Начнем с тем. Во-первых, удаляйте лишние и неиспользуемые темы: стандартные темы типо twentysixteen, twentyseventeen или twentyfifteen можно безболезненно деинсталлировать с сайта. Во-вторых, можно переименовывать темы на свои уникальные, дабы искажать информацию об установленном шаблоне. Тут палка о двух концах, мы не будем получать обновления, это было б неплохо для тяжелых тем, особенно с функционалом магазина. С другой стороны будем уверены, что обновление не перепишет наши правки.

Следующим шагом будем убирать информацию, которые оставляют плагины. Достаточно заглянуть в код страницы и лицезреть в комментариях различного рода информацию, от версий и названий плагинов до информации отладки. Приведу некоторые примеры:

<!-- This site is optimized with the Yoast SEO plugin v3.4.2  -->

<!-- platinum seo pack 1.3.8 --> <!-- /platinum one seo pack -->

<!-- Powered by WPtouch: 4.0.4 -->

Такой мусор нам совсем ни к чему, в большинстве случаев это можно откючить в настройках плагинов, реже придется лезть в код.

Как отключить Emoji в WordPress

Добавляем в functions.php следующий код:

remove_action( 'wp_head', 'print_emoji_detection_script', 7 );

remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

remove_action( 'wp_print_styles', 'print_emoji_styles' );

remove_action( 'admin_print_styles', 'print_emoji_styles' ); 

remove_filter( 'the_content_feed', 'wp_staticize_emoji' );

remove_filter( 'comment_text_rss', 'wp_staticize_emoji' ); 

remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );

add_filter( 'tiny_mce_plugins', 'disable_wp_emojis_in_tinymce' );

function disable_wp_emojis_in_tinymce( $plugins ) {

    if ( is_array( $plugins ) ) {

        return array_diff( $plugins, array( 'wpemoji' ) );

    } else {

        return array();

    }

}

Как полностью отключить REST API в Wordpress

В последних версиях ворпресса появилась очередная фича для разработчиков, позволяющая более гибко и удобно создавать различные приложения. REST API позволяет использовать возможности WP Query посредством простых запросов и всё через wp-json. Простым блогам, не использующим данную технологию, эти нововведения принесли лишь дополнительные хлопоты: в вебмастерах стали индексироваться непонятные страницы, содержащие в адресе /wp-json/wp/v2/posts или /wp-json/wp/v2/users/. Нет повода для радости и в том, что хакеры тоже нашли применение новому апи и во всю эксплуатировали найденные дыры для веб-спама и создания дорвеев. И я думаю, что это далеко не последняя обнаруженная уязвимость в фреймворке REST API. Именно поэтому для тех, кто не использует на своём сайте данные фишки, то их без зазрения совести можно и нужно отключить. Делается это как также в файле функций темы необходимо добавить следующий код:

// Отключаем сам REST API
add_filter('rest_enabled', '__return_false');

// Отключаем фильтры REST API
remove_action( 'xmlrpc_rsd_apis',            'rest_output_rsd' );
remove_action( 'wp_head',                    'rest_output_link_wp_head', 10, 0 );
remove_action( 'template_redirect',          'rest_output_link_header', 11, 0 );
remove_action( 'auth_cookie_malformed',      'rest_cookie_collect_status' );
remove_action( 'auth_cookie_expired',        'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_username',   'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_hash',       'rest_cookie_collect_status' );
remove_action( 'auth_cookie_valid',          'rest_cookie_collect_status' );
remove_filter( 'rest_authentication_errors', 'rest_cookie_check_errors', 100 );

// Отключаем события REST API
remove_action( 'init',          'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
remove_action( 'parse_request', 'rest_api_loaded' );

// Отключаем Embeds связанные с REST API
remove_action( 'rest_api_init',          'wp_oembed_register_route'              );
remove_filter( 'rest_pre_serve_request', '_oembed_rest_pre_serve_request', 10, 4 );

remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
// если собираетесь выводить вставки из других сайтов на своем, то закомментируйте след. строку.
remove_action( 'wp_head',                'wp_oembed_add_host_js'                 ); 

Если при этом возникают проблемы с работоспособностью плагинов, к примеру, с отправкой форм в Contact Form 7 - то удалите или закомментируйте следующие строки:

remove_action( 'init',          'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
remove_action( 'parse_request', 'rest_api_loaded' );

И напоследок, скину список стандартных файлов, которые обнаруживают популярные сканеры (cmsmap в частности):

/readme.html

/license.txt

/wp-includes/images/crystal/license.txt

/wp-includes/images/crystal/license.txt

/wp-includes/js/plupload/license.txt

/wp-includes/js/tinymce/license.txt

/wp-includes/js/swfupload/license.txt

/wp-includes/ID3/license.txt

/wp-includes/ID3/readme.txt

/wp-includes/ID3/license.commercial.txt

Что с ними делать, уже вам решать, удалять, запрещать доступ или оставлять как есть.

Если понравилась статья, поделитесь с ней друзьями. В комментариях жду ваши советы по заметанию следов вордпресса.

Комментарии   
+3 # Антон 10.07.2016 14:43
Спасибо за статью, жду её дополнения!

Убрать версионность скриптов и стилей можно так:

function _remove_script_ version( $src ){
$parts = explode( '?', $src );
return $parts[0];}
add_filter( 'script_loader_ src', '_remove_script _version', 15, 1 );
add_filter( 'style_loader_s rc', '_remove_script _version', 15, 1 );

Добавьте этот код в файл function.php в папке вашей темы на WP.
Ответить | Ответить с цитатой | Цитировать
0 # Protect Your Site 10.07.2016 14:49
Спасибо за совет, обязательно потестируем это решение
Ответить | Ответить с цитатой | Цитировать
-3 # Optimizator 15.07.2016 14:55
Пришла по делу, а решила поофтопить, с Вашего позволения, и похулиганить, в том числе, с именем. Это что "Затираем признаки Wordpress - удаляем следы присутствия"? Картинка подписана?. Просто сам просится H2! Лучше бы H2!
Ответить | Ответить с цитатой | Цитировать
Добавить комментарий