2026年11月12日

2026年11月12日

Ẩn thông tin phiên bản WordPress: thẻ generator, ver=, readme.html

Đây là phiên bản được bản địa hóa từ bài viết gốc tiếng Nhật. Đọc bài gốc tiếng Nhật

Ở trạng thái ban đầu, WordPress ghi số phiên bản của chính nó vào HTML và feed của trang. Kẻ tấn công có thể nhìn vào đó để làm manh mối kiểm tra xem phiên bản đó có lỗ hổng đã biết hay không. Bài viết này kiểm tra những nơi phiên bản được hiển thị và giải thích các bước để ẩn nó. Nội dung được cập nhật tại thời điểm tháng 10/2026.

Điều đầu tiên cần biết là ẩn phiên bản chỉ là biện pháp hỗ trợ. Vì vẫn có cách đoán phiên bản từ nội dung của tệp CSS và JavaScript, nên ẩn đi chưa chắc ngăn được việc bị nhận diện. Điều hiệu quả nhất là luôn cập nhật WordPress core, plugin và theme lên bản mới nhất.

Những nơi phiên bản được hiển thị

Vị trí Nội dung hiển thị Cách xử lý
<head> của HTML Thẻ như <meta name="generator" content="WordPress 6.9.4"> Bộ lọc the_generator
Feed RSS / Atom Dòng như <generator>https://wordpress.org/?v=6.9.4</generator> Cũng dùng bộ lọc the_generator
URL của CSS / JavaScript ?ver= như style.min.css?ver=6.9.4 Bộ lọc style_loader_src và script_loader_src
HTTP header X-Powered-By: PHP/8.3.x (là phiên bản PHP chứ không phải WordPress) expose_php trong php.ini
readme.html Cho biết đang dùng WordPress (readme.html hiện nay không ghi số phiên bản) Từ chối truy cập

Thông tin site mà /wp-json/ của REST API trả về (tên, mô tả, URL, múi giờ, namespace, v.v.) không chứa phiên bản WordPress. Bạn không cần cắt bớt đầu ra của REST API chỉ để ẩn phiên bản.

Bước 1: Kiểm tra trạng thái hiển thị hiện tại

Hãy thay bằng URL site của bạn và chạy trên máy tính của bạn hoặc trên máy chủ. Nếu đang dùng plugin cache hoặc CDN, hãy xóa cache sau khi thay đổi rồi mới kiểm tra.

# Thẻ generator trong HTML
curl -s https://example.com/ | grep -i 'name="generator"'

# generator của feed
curl -s https://example.com/feed/ | grep -i '<generator>'

# Danh sách các giá trị ver= gắn vào CSS và JS
curl -s https://example.com/ | grep -oE 'ver=[0-9][0-9.]*' | sort | uniq -c

# X-Powered-By trong HTTP header
curl -sI https://example.com/ | grep -i 'x-powered-by'

# readme.html có đọc được không (200 là đọc được)
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html

Nếu danh sách ver= có giá trị trùng với phiên bản WordPress hiển thị trong "Bảng tin" (Dashboard) → "Cập nhật" (Updates) của trang quản trị, nghĩa là từ CSS hoặc JS đó có thể biết được phiên bản WordPress. Khi WordPress core hoặc theme nạp CSS / JS mà không chỉ định phiên bản, phiên bản WordPress sẽ được đưa vào ver=.

Bước 2: Quyết định nơi đặt mã

Mã trong bài viết này đặt ở một trong hai nơi sau.

  • mu-plugin (khuyến nghị): đặt tệp PHP vào thư mục wp-content/mu-plugins/ (tạo nếu chưa có), nó sẽ được nạp mà không cần thao tác kích hoạt. Hiệu quả vẫn giữ nguyên khi bạn đổi theme
  • functions.php của child theme: nếu viết vào functions.php của theme cha, nó sẽ mất khi theme được cập nhật

Nếu dùng mu-plugin, hãy gộp mã của bước tiếp theo vào một tệp và lưu với tên như wp-content/mu-plugins/hide-wp-version.php.

Bước 3: Ẩn phiên bản trong thẻ generator và ver=

<?php
/**
 * Plugin Name: Hide WordPress Version
 * Description: Ẩn phiên bản WordPress xuất hiện trong thẻ generator và ver= của CSS / JS.
 */

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

// Làm trống <meta name="generator"> của HTML và <generator> của feed.
add_filter( 'the_generator', '__return_empty_string' );

/**
 * Chỉ khi ver= của CSS / JS trùng với phiên bản WordPress thì mới thay bằng giá trị khác.
 * Vì thay chứ không xóa ver=, cache của trình duyệt vẫn được làm mới sau khi cập nhật 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 );

Các điểm chính như sau.

  • Bộ lọc the_generator có tác dụng với cả thẻ generator của HTML lẫn generator của feed. remove_action( 'wp_head', 'wp_generator' ); chỉ xóa thẻ trong HTML nên không có tác dụng với feed
  • Nếu xóa hết ?ver=, khi cập nhật plugin hoặc theme, trình duyệt có thể tiếp tục dùng CSS / JS cũ. Đoạn mã trên chỉ thay bằng một chuỗi khác được tạo từ phiên bản khi giá trị trùng với phiên bản WordPress. Khi bạn cập nhật WordPress, giá trị cũng đổi, nên cache được làm mới
  • Các ver= mà plugin hoặc theme gán số phiên bản riêng thì không bị thay đổi

Sau khi lưu, hãy dùng các lệnh ở Bước 1 để xác nhận generator không còn xuất hiện và trong danh sách ver= không còn phiên bản WordPress. Nếu đang dùng plugin cache, hãy xóa cache rồi mới kiểm tra.

Bước 4: Chặn header X-Powered-By

X-Powered-By là header do PHP chứ không phải WordPress thêm vào, và nó cho biết phiên bản PHP. Để chặn, hãy đặt expose_php là Off trong tệp cấu hình PHP (php.ini). Thiết lập này chỉ thay đổi được trong php.ini.

expose_php = Off

Đây là ví dụ khi dùng PHP-FPM trên Ubuntu VPS (8.3 hãy khớp với phiên bản PHP bạn đang dùng).

# Kiểm tra thiết lập hiện tại
grep -n '^expose_php' /etc/php/8.3/fpm/php.ini

# Sau khi sửa, khởi động lại PHP-FPM
sudo systemctl restart php8.3-fpm

php.ini của gói Ubuntu có sẵn expose_php = Off ở trạng thái ban đầu. Nếu header vẫn hiện, hãy kiểm tra xem có đang dùng một php.ini khác không. Trên hosting thuê, có nơi cho đổi trong thiết lập PHP của trang quản trị, có nơi không.

Khi không đổi được php.ini, cũng có cách gỡ header bằng mã WordPress. Tuy nhiên send_headers là hook chạy khi WordPress xuất các trang phía front, nên không có tác dụng với trang quản trị và trang đăng nhập.

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

Bước 5: Từ chối truy cập vào readme.html và license.txt

readme.html và license.txt là các tệp của WordPress core. readme.html hiện nay không ghi số phiên bản, nhưng vẫn cho biết trang đang dùng WordPress.

Dù xóa thì chúng cũng được khôi phục khi cập nhật WordPress core. Từ chối truy cập ở máy chủ Web ít công sức hơn là xóa.

Trường hợp Apache (.htaccess)

Thêm vào .htaccess trong thư mục WordPress. Phần giữa # BEGIN WordPress và # END WordPress sẽ do WordPress ghi lại, nên hãy viết bên ngoài phần đó. Đây là cách viết của Apache 2.4 (Order và Deny from all là cách viết cũ của Apache 2.2).

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

Trường hợp Nginx

Thêm vào khối server của site, kiểm tra cấu hình rồi tải lại.

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

Sau khi thêm, hãy chạy curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html và xác nhận nhận được 403.

Những điều ẩn đi cũng không ngăn được

  • Nội dung các tệp CSS / JS của WordPress khác nhau đôi chút theo từng phiên bản, nên nếu tải tệp về và so sánh thì vẫn đoán được phiên bản
  • Từ readme.txt hoặc ver= của plugin và theme, đôi khi biết được phiên bản plugin. Thứ dễ bị nhắm đến là lỗ hổng của plugin hơn là của core
  • Với những người đăng nhập được vào trang quản trị, phiên bản vẫn hiển thị như trước

Vì vậy, cùng với việc ẩn phiên bản, hãy cập nhật core, plugin, theme, xóa các plugin không dùng, tắt chức năng chỉnh sửa tệp trong trang quản trị, v.v.

Tổng kết

  • Phiên bản chủ yếu xuất hiện ở generator của HTML và feed, và ?ver= của CSS / JS. /wp-json/ của REST API không chứa phiên bản WordPress
  • Có thể xóa generator ở cả HTML và feed bằng add_filter( 'the_generator', '__return_empty_string' );
  • Đừng xóa ?ver=, mà chỉ thay các giá trị trùng với phiên bản WordPress, như vậy không làm gián đoạn việc làm mới cache
  • Chặn X-Powered-By bằng expose_php = Off trong php.ini
  • readme.html dù xóa cũng quay lại sau khi cập nhật, nên hãy từ chối truy cập ở máy chủ Web
  • Ẩn đi chỉ là biện pháp hỗ trợ; điều quan trọng nhất là tiếp tục cập nhật

Bài viết liên quan:

Có câu hỏi về WordPress? Đơn vị xuất bản trang này ở Nhật Bản và trả lời bằng tiếng Nhật. Liên hệ (tiếng Nhật)

お気軽にご相談ください

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