2026年11月12日

2026年11月12日

Как скрыть версию WordPress: тег generator, ver=, readme.html

Эта статья — локализованная версия японского оригинала. Читать японский оригинал

По умолчанию WordPress выводит номер своей версии в HTML страниц и в фидах. Злоумышленник может по нему определить, есть ли в этой версии известные уязвимости. В статье показано, где отображается версия и как её скрыть. Материал актуален на октябрь 2026 года.

Сначала нужно понимать, что скрытие версии — вспомогательная мера. Версию можно угадать, например, по содержимому файлов CSS и JavaScript, поэтому даже после скрытия определение версии не обязательно станет невозможным. Лучше всего помогает поддержание ядра WordPress, плагинов и тем в актуальном состоянии.

Где отображается версия

Где Что отображается Что делать
<head> в HTML Тег вроде <meta name="generator" content="WordPress 6.9.4"> Фильтр the_generator
Фиды RSS и Atom Строка вроде <generator>https://wordpress.org/?v=6.9.4</generator> Тоже фильтр the_generator
URL файлов CSS и JavaScript Параметр ?ver=, например style.min.css?ver=6.9.4 Фильтры style_loader_src и script_loader_src
HTTP-заголовки X-Powered-By: PHP/8.3.x (версия PHP, а не WordPress) expose_php в php.ini
readme.html Сведения о том, что используется WordPress (номера версии в нынешнем readme.html нет) Закрыть доступ

В данных сайта, которые возвращает /wp-json/ REST API (название, описание, URL, часовой пояс, пространства имён и т. д.), версии WordPress нет. Урезать вывод REST API ради скрытия версии не нужно.

Шаг 1. Проверьте, что отображается сейчас

Подставьте URL своего сайта и выполните команды на своём компьютере или на сервере. Если вы используете плагины кеширования или CDN, после изменений сначала очистите кеш, а затем проверяйте.

# Тег generator в HTML
curl -s https://example.com/ | grep -i 'name="generator"'

# generator в фиде
curl -s https://example.com/feed/ | grep -i '<generator>'

# Список значений ver= у CSS и JS
curl -s https://example.com/ | grep -oE 'ver=[0-9][0-9.]*' | sort | uniq -c

# Заголовок HTTP X-Powered-By
curl -sI https://example.com/ | grep -i 'x-powered-by'

# Доступен ли readme.html (200 — доступен)
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html

Если в списке значений ver= есть то же значение, что показано в админ-панели в разделе «Консоль» (Dashboard) → «Обновления» (Updates) как версия WordPress, то по этим CSS и JS версию WordPress можно определить. Если ядро WordPress или тема подключают CSS и JS без указания версии, в ver= попадает версия WordPress.

Шаг 2. Решите, куда поместить код

Код из этой статьи размещается в одном из двух мест.

  • mu-plugin (рекомендуется): если положить PHP-файл в папку wp-content/mu-plugins/ (создайте её, если нет), он загружается без активации. Эффект сохранится и при смене темы
  • functions.php дочерней темы: если писать в functions.php родительской темы, изменения пропадут при её обновлении

Если вы выбираете mu-plugin, соберите код следующего шага в один файл и сохраните его с именем вроде wp-content/mu-plugins/hide-wp-version.php.

Шаг 3. Скройте версию в теге generator и в ver=

<?php
/**
 * Plugin Name: Hide WordPress Version
 * Description: скрывает версию WordPress в теге generator и в ver= у CSS и JS.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// Очищаем <meta name="generator"> в HTML и <generator> в фиде.
add_filter( 'the_generator', '__return_empty_string' );

/**
 * Заменяем ver= у CSS и JS другим значением, только если оно совпадает с версией WordPress.
 * Параметр не удаляется, а заменяется, поэтому после обновления WordPress кеш браузера обновляется.
 */
function wpdr_replace_wp_version_query( $src ) {
	if ( ! is_string( $src ) || '' === $src ) {
		return $src;
	}

	$query = wp_parse_url( $src, PHP_URL_QUERY );
	if ( empty( $query ) ) {
		return $src;
	}

	parse_str( $query, $args );
	$wp_version = get_bloginfo( 'version' );

	if ( isset( $args['ver'] ) && $args['ver'] === $wp_version ) {
		$src = add_query_arg( 'ver', substr( wp_hash( $wp_version ), 0, 10 ), $src );
	}

	return $src;
}
add_filter( 'style_loader_src', 'wpdr_replace_wp_version_query', 20 );
add_filter( 'script_loader_src', 'wpdr_replace_wp_version_query', 20 );

Основные моменты.

  • Фильтр the_generator действует и на тег generator в HTML, и на generator в фидах. remove_action( 'wp_head', 'wp_generator' ); убирает только тег в HTML, а на фиды не влияет
  • Если убрать ?ver= целиком, после обновления плагинов или тем браузер может продолжить использовать старые CSS и JS. Код выше заменяет значение на другую строку, полученную из версии, только если оно совпадает с версией WordPress. После обновления WordPress значение меняется, поэтому кеш обновляется
  • Значения ver=, в которых плагины и темы указывают собственные номера версий, не меняются

После сохранения проверьте командами из шага 1, что generator не выводится, а в списке ver= не осталось версии WordPress. Если вы используете плагины кеширования, сначала очистите кеш.

Шаг 4. Отключите заголовок X-Powered-By

Заголовок X-Powered-By добавляет не WordPress, а PHP, и по нему видна версия PHP. Чтобы отключить его, в файле настроек PHP (php.ini) установите expose_php в Off. Эту настройку можно менять только в php.ini.

expose_php = Off

Пример для VPS с Ubuntu и PHP-FPM (8.3 замените версией PHP, которую вы используете).

# Проверить текущую настройку
grep -n '^expose_php' /etc/php/8.3/fpm/php.ini

# После изменения перезапустить PHP-FPM
sudo systemctl restart php8.3-fpm

В php.ini из пакетов Ubuntu по умолчанию уже стоит expose_php = Off. Если заголовок всё же выводится, проверьте, не используется ли другой php.ini. На арендованных хостингах эту настройку иногда можно менять в параметрах PHP в админ-панели, а иногда нельзя.

Если php.ini изменить нельзя, заголовок можно убрать и кодом WordPress. Но send_headers — хук, срабатывающий, когда WordPress выводит страницы публичной части сайта, поэтому на админ-панель и страницу входа он не действует.

add_action( 'send_headers', function () {
	header_remove( 'X-Powered-By' );
} );

Шаг 5. Закройте доступ к readme.html и license.txt

readme.html и license.txt — файлы ядра WordPress. В нынешнем readme.html номера версии нет, но по нему видно, что используется WordPress.

Даже если их удалить, после обновления ядра WordPress они вернутся. Закрыть доступ на веб-сервере проще, чем удалять.

Для Apache (.htaccess)

Добавьте в .htaccess в папке WordPress. Между # BEGIN WordPress и # END WordPress WordPress переписывает содержимое сам, поэтому пишите за пределами этого блока. Это синтаксис Apache 2.4 (Order и Deny from all — старая запись Apache 2.2).

<FilesMatch "^(readme\.html|license\.txt)$">
    Require all denied
</FilesMatch>

Для Nginx

Добавьте в блок server сайта, проверьте конфигурацию и перезагрузите её.

location ~* ^/(readme\.html|license\.txt)$ {
    deny all;
}
sudo nginx -t && sudo systemctl reload nginx

После добавления выполните curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html и убедитесь, что возвращается 403.

Что скрытие не предотвращает

  • Содержимое файлов CSS и JS WordPress немного отличается от версии к версии, поэтому, скачав файлы и сравнив их, версию можно угадать
  • По readme.txt и ver= плагинов и тем иногда видны версии плагинов. Чаще атакуют уязвимости плагинов, а не ядра
  • Тем, кто может войти в админ-панель, версия по-прежнему показывается

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

Итоги

  • Версия видна главным образом в generator в HTML и фидах и в ?ver= у CSS и JS. В /wp-json/ REST API версии WordPress нет
  • add_filter( 'the_generator', '__return_empty_string' ); убирает generator и в HTML, и в фидах
  • ?ver= лучше не убирать, а заменять только значение, совпадающее с версией WordPress: тогда не нарушится обновление кеша
  • X-Powered-By отключается директивой expose_php = Off в php.ini
  • readme.html после удаления возвращается при обновлении, поэтому закройте доступ к нему на веб-сервере
  • Скрытие версии — вспомогательная мера, а самое важное — продолжать обновления

Похожие статьи:

Есть вопросы по WordPress? Издатель сайта находится в Японии и отвечает по-японски. Связаться (по-японски)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲