2026年11月12日
2026年11月12日
WordPress 버전 정보를 숨기는 방법|generator 태그·ver=·readme.html
이 글은 일본어 원문을 현지화한 버전입니다. 일본어 원문 보기
WordPress는 초기 상태에서 페이지의 HTML이나 피드에 자신의 버전 번호를 출력합니다. 공격자가 이를 보고 알려진 취약점이 있는 버전인지 조사하는 단서로 삼는 경우가 있습니다. 이 글에서는 버전이 표시되는 위치를 확인하고 숨기는 절차를 설명합니다. 내용은 2026년 10월 시점의 것입니다.
먼저 알아 두셔야 할 점은 버전을 숨기는 것은 보조적인 대책이라는 것입니다. CSS나 JavaScript 파일의 내용 등으로 버전을 추측하는 방법도 있으므로, 숨겨도 특정을 막을 수 있다고는 할 수 없습니다. 가장 효과적인 것은 WordPress 코어·플러그인·테마를 항상 최신으로 유지하는 것입니다.
버전이 표시되는 위치
| 위치 | 표시되는 내용 | 대처 |
|---|---|---|
HTML의 <head> |
<meta name="generator" content="WordPress 6.9.4"> 같은 태그 |
the_generator 필터 |
| RSS·Atom 피드 | <generator>https://wordpress.org/?v=6.9.4</generator> 같은 줄 |
마찬가지로 the_generator 필터 |
| CSS·JavaScript의 URL | style.min.css?ver=6.9.4 같은 ?ver= |
style_loader_src·script_loader_src 필터 |
| HTTP 헤더 | X-Powered-By: PHP/8.3.x(WordPress가 아니라 PHP의 버전) |
php.ini의 expose_php |
readme.html |
WordPress를 사용하고 있다는 사실(현재의 readme.html에는 버전 번호가 적혀 있지 않습니다) | 접근을 거부한다 |
REST API의 /wp-json/이 반환하는 사이트 정보(이름·설명·URL·시간대·네임스페이스 등)에는 WordPress 버전이 포함되어 있지 않습니다. 버전을 숨길 목적으로 REST API의 출력을 줄일 필요는 없습니다.
1단계: 현재 표시 상태 확인하기
자신의 사이트 URL로 바꿔서 내 컴퓨터나 서버에서 실행합니다. 캐시 계열 플러그인이나 CDN을 사용 중이라면 변경 후에 캐시를 삭제한 뒤 확인하세요.
# HTML의 generator 태그
curl -s https://example.com/ | grep -i 'name="generator"'
# 피드의 generator
curl -s https://example.com/feed/ | grep -i '<generator>'
# CSS·JS에 붙어 있는 ver= 값 목록
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를 불러올 때 버전을 지정하지 않으면 WordPress 버전이 ver=에 들어갑니다.
2단계: 코드를 둘 위치 정하기
이 글의 코드는 다음 둘 중 한 곳에 둡니다.
- mu-plugin(추천):
wp-content/mu-plugins/폴더(없으면 만든다)에 PHP 파일을 두면 활성화 조작 없이 로드됩니다. 테마를 바꿔도 효과가 이어집니다 - 자식 테마의 functions.php: 부모 테마의 functions.php에 작성하면 테마 업데이트로 사라집니다
mu-plugin으로 만든다면 wp-content/mu-plugins/hide-wp-version.php 같은 이름으로, 다음 단계의 코드를 하나의 파일에 모아 저장합니다.
3단계: generator 태그와 ver=의 버전 숨기기
<?php
/**
* Plugin Name: Hide WordPress Version
* Description: generator 태그와, CSS·JS의 ver=에 나오는 WordPress 버전을 숨긴다.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// HTML의 <meta name="generator"> 와, 피드의 <generator>를 비운다.
add_filter( 'the_generator', '__return_empty_string' );
/**
* CSS·JS의 ver=가 WordPress 버전과 같을 때만 다른 값으로 치환한다.
* ver=를 지우는 것이 아니라 치환하므로, 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필터는 HTML의 generator 태그와 피드의 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
Ubuntu 패키지의 php.ini는 초기 상태에서 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)의 경우
WordPress 폴더에 있는 .htaccess에 추가합니다. # 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이 반환되는지 확인합니다.
숨겨도 막을 수 없는 것
- WordPress의 CSS·JS 파일 내용은 버전마다 조금씩 다르므로, 파일을 가져와 비교하면 버전을 추측할 수 있습니다
- 플러그인이나 테마의
readme.txt나ver=로 플러그인 버전을 알 수 있는 경우가 있습니다. 공격 대상이 되기 쉬운 것은 코어보다 플러그인의 취약점입니다 - 관리자 화면에 로그인할 수 있는 사람에게는 버전이 지금까지처럼 표시됩니다
따라서 버전을 숨기는 것과 함께 코어·플러그인·테마 업데이트, 사용하지 않는 플러그인 삭제, 관리자 화면의 파일 편집 비활성화 등을 실시하세요.
정리
- 버전이 노출되는 곳은 HTML과 피드의 generator, CSS·JS의
?ver=가 주된 위치. REST API의/wp-json/에는 WordPress 버전이 포함되지 않는다 add_filter( 'the_generator', '__return_empty_string' );로 HTML과 피드 양쪽의 generator를 지울 수 있다?ver=는 지우지 않고 WordPress 버전과 같은 값만 치환하면 캐시 갱신을 막지 않을 수 있다X-Powered-By는 php.ini의expose_php = Off로 차단한다readme.html은 삭제해도 업데이트하면 돌아오므로 웹 서버에서 접근을 거부한다- 숨기는 것은 보조적인 대책이며, 업데이트를 계속하는 것이 가장 중요하다
관련 글:
- WordPress 보안 헤더 설정 방법|.htaccess·Nginx·functions.php별
- WordPress REST API 접근을 제한하는 방법
- WordPress 테마·플러그인 파일 편집기를 비활성화하기|DISALLOW_FILE_EDIT
WordPress에 대해 궁금한 점이 있으신가요? 이 사이트의 운영사는 일본에 있으며 일본어로 답변합니다. 문의하기(일본어)