워드프레스 XML-RPC: 비활성화 방법 3가지 & xmlrpc.php 공격 판별 방법 | Jetpack 예외

공정위 광고 문구 Ver 3.1
공정위 광고 문구 Ver 3.2(모바일 전용)

워드프레스 웹사이트 접근 기록에 xmlrpc.php 요청이 같은 IP에서 수백 건씩 이어진다면 워드프레스 XML-RPC를 노린 비밀번호 대입입니다. 워드프레스 사이트 여러 개를 운영하는 Nginx + Apache 구성 서버의 하루 접근 기록 8,624건을 분류하고, 비활성화 방법 세 가지를 직접 적용해 응답 코드를 확인한 결과, 어느 층에서 막아야 PHP 실행까지 줄어드는지 정리했습니다.

XML-RPC는 HTTP로 XML 문서를 주고받아 워드프레스 기능을 원격으로 호출하는 규약이며, 워드프레스 3.5부터는 설정 화면의 켜고 끄는 항목이 없어져 설치 직후부터 켜진 상태로 운영됩니다.

1️⃣ xmlrpc.php의 역할과 사용하는 곳

REST API가 생긴 뒤로 [xmlrpc.php]를 더 이상 사용되지 않는 파일로 여기기 쉽지만, Jetpack은 지금도 이 파일을 통해 WordPress.com과 사이트를 연결합니다. Jetpack 공식 문서는 XML-RPC 연결에 의존한다고 명시하고 있으며, XML-RPC를 기본 차단하는 호스팅에서는 Jetpack 연결 자체가 실패합니다. 요즘도 사무실에 팩스 번호 하나는 남겨 두는 것과 같습니다.

워드프레스 7.1 기준으로 이 파일이 받는 메서드는 77개이며, 글과 미디어, 댓글을 다루는 wp 계열 50개와 옛 블로그 규약(MetaWeblog, MovableType, Blogger) 23개, 핑백 2개, 시험용 demo 2개로 구성됩니다.

wp 계열은 요청 본문에 담긴 사용자명과 비밀번호로 로그인하므로 로그인 화면을 거치지 않습니다. 글 작성과 수정, 미디어 업로드, 댓글 관리가 모두 이 계열이며, 옛 블로그 규약 23개는 다른 블로그 도구와 같은 방식으로 글을 주고받기 위해 남겨 둔 메서드입니다.

demo.sayHello는 워드프레스 XML-RPC에 들어 있는 시험용 호출입니다. 보내면 [Hello!] 한 마디만 돌려주는데, 로그인이 필요 없어 XML-RPC가 동작하는지 확인하는 용도로 사용합니다. 짝으로 두 수를 더해 돌려주는 demo.addTwoNumbers가 있습니다.

모두 POST로 XML 본문을 보내야 응답하며, 브라우저로 주소를 열면 [XML-RPC server accepts POST requests only.] 문구와 함께 405가 돌아옵니다.

핑백도 이 파일의 몫입니다. 글을 발행하면 본문에 링크한 사이트의 xmlrpc.php로 핑백을 보내고, 받는 쪽 서버는 보낸 주소를 직접 열어 링크가 실제로 있는지 확인합니다.

🧭 xmlrpc.php로 들어오는 요청과 처리
wp-admin 보안설명 다이어그램
📨 보내는 쪽
↓
입구
xmlrpc.php
POST로 보낸 XML 본문만 처리
405 · XML-RPC server accepts POST requests only.
메서드 77개
wp.*글 · 미디어 · 댓글 50개
metaWeblog · mt · blogger옛 블로그 규약 23개
pingback.*핑백 2개
demo.*동작 확인용 시험 호출 2개
결과
WordPress.com과의 연결 유지
요청 본문의 사용자명·비밀번호 확인 → 글 작성·수정
보낸 주소를 서버가 직접 열어 링크 확인
로그인 없이 Hello! 응답
처리 없음
Jetpack은 WordPress.com과의 연결을 이 파일로 유지하므로, 파일을 막으면 연결이 끊깁니다.
외부 발행 도구는 요청 본문에 담은 사용자명과 비밀번호로 로그인하며, 로그인 화면을 거치지 않습니다.
글에 링크된 사이트의 xmlrpc.php로 핑백을 보내고, 받는 쪽 서버는 보낸 주소를 직접 열어 링크를 확인합니다.
demo.sayHello는 XML-RPC가 동작하는지 확인하는 시험용 호출로, 로그인 없이 [Hello!] 한 마디로 응답합니다.
브라우저로 주소를 열면 [XML-RPC server accepts POST requests only.] 문구와 함께 405가 돌아옵니다.

2️⃣ 접근 기록으로 보는 xmlrpc.php 공격

비밀번호 대입은 로그인 화면을 거치지 않고 [xmlrpc.php]로 들어옵니다. 워드프레스 사이트 여러 개를 운영하는 Nginx + Apache 구성 서버의 10월 14일 0시부터 20시까지 접근 기록에서 POST /xmlrpc.php 요청은 8,624건, IP는 72개였고, 그중 19개 IP가 정확히 300건씩 보냈습니다.

한 IP는 14시 9분부터 37분까지 28분 동안 300건을 보냈으며, 5~6초 간격이 끝까지 일정했습니다. 요청 8,524건은 User-Agent에 Jetpack 또는 WordPress.com을 적고 들어왔고, [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)]처럼 실제 Jetpack 형식을 흉내 낸 값을 같은 IP가 여러 개 번갈아 사용했습니다.

같은 날 14시 전까지는 보안 플러그인의 XML-RPC 끄기가 이 요청을 홈으로 302 돌려보냈고, 14시 이후 Nginx에서 차단한 뒤에는 403으로 끝났습니다. 302는 본문이 0바이트라도 요청마다 PHP가 실행된 결과이고, 403은 PHP를 거치지 않은 응답입니다.

🧭 접근 기록 한 줄로 보는 xmlrpc.php 공격
설명 다이어그램
🛡️ 서버 상태
접근 기록 한 줄(Nginx access.log)
203.0.113.25IP[14/Oct/2026:14:09:04 +0900]시각"POST /xmlrpc.php HTTP/1.1"요청302403상태0153바이트"Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)"User-Agent
PHP 실행 · 홈으로 302PHP 미경유 · Nginx 기본 403 페이지
보안 플러그인이 XML-RPC를 끈 상태에서는 요청을 홈으로 돌려보내는 302가 기록됩니다. 본문은 0바이트지만 그 302를 내기 위해 PHP가 실행됩니다.
Nginx에서 차단하면 403과 기본 오류 페이지 153바이트가 기록되고, PHP는 실행되지 않습니다.
같은 IP의 요청
14:09:0414:37:20
28분 동안 300건, 5~6초 간격
0시~20시 POST 8,624건IP 72개300건씩 보낸 IP 19개Jetpack·WordPress.com 사칭 UA 8,524건

3️⃣ system.multicall과 비밀번호 대입

[system.multicall]로 요청 한 번에 비밀번호 수백 개를 시험한다는 설명이 많지만, 워드프레스는 한 요청 안에서 로그인이 한 번 실패하면 나머지 호출의 비밀번호를 대조하지 않습니다. 첫 호출만 wp_authenticate를 거치고, 이후 호출은 검사 없이 같은 오류 [Incorrect username or password.]로 응답합니다.

호출 수만큼 응답은 그대로 돌아오므로, 틀린 비밀번호 100개를 담은 요청 하나에 23KB 응답으로 오류 100개가 0.12초 만에 돌아옵니다. 같은 요청 안에서 맞는 비밀번호를 뒤에 두면 앞 호출의 실패 때문에 함께 거부되고, 앞에 두면 그 호출만 성공합니다. 비밀번호 대조는 한 번이지만 XML 해석과 워드프레스 로딩은 요청마다 반복되므로, 이 공격의 서버 부담은 로그인 검사가 아니라 요청 수 자체에서 발생합니다.

4️⃣ XML-RPC 비활성화 방법 3가지와 응답 코드

플러그인에서 XML-RPC를 꺼도 [xmlrpc.php] 요청은 PHP까지 들어옵니다. 필터로 끈 상태에서 호출 100개짜리 요청을 보내도 HTTP 200에 오류 100개(24KB)가 그대로 돌아왔습니다. 어느 층에서 거부하느냐에 따라 방법은 셋으로 나뉘며, 응답 코드가 각각 다릅니다.

1. 코드로 xmlrpc_enabled 필터 끄기

테마의 functions.php에 [xmlrpc_enabled] 필터를 false로 돌리는 add_filter 한 줄을 넣으면 됩니다. 이 상태에서 로그인이 필요한 호출은 [XML-RPC services are disabled on this site.] 오류와 HTTP 405로 거부되지만, 로그인이 필요 없는 시험용 호출 demo.sayHello는 여전히 200으로 응답합니다.

2. 플러그인 설정으로 끄기: Perfmatters·Hide My WP

Perfmatters 및 Hide My WP 등의 플러그인에서 Disable XML-RPC 설정으로 비활성화하는 방법입니다. Hide My WP는 위와 같은 필터 방식이라 응답도 같지만, Perfmatters는 같은 필터에 더해 [xmlrpc.php] 직접 요청을 403으로 끝내고 핑백 헤더와 핑백 링크까지 제거하므로, 끄고 나면 GET과 POST 모두 403으로 응답합니다. 다만 403을 내기 위해 워드프레스가 init 단계까지 실행되므로, 응답까지 0.13~0.15초로 열려 있을 때와 같은 시간이 걸리고 PHP 부담은 남습니다.

🔌 플러그인 설정에서 XML-RPC 끄기
📍 Settings › Perfmatters › General › Core › Disable XML-RPC
토글을 켜고 [Save Changes]를 누르면 아래 방문자 화면이 바뀝니다.
관리자 화면
Settings saved.
perfmatters
⚙ GeneralVersion 2.6.8
Core
Disable Emojis?
Disable Dashicons?
Disable Embeds?
Disable XML-RPC?
Remove RSD Link?
Remove jQuery Migrate?
Hide WP Version?
Remove Shortlink?
Disable RSS Feeds?
Remove RSS Feed Links?
Disable Self Pingbacks?
Disable REST API?
Remove REST API Links?
Disable Google Maps?
Disable Password Meter?
Disable Comments?
Remove Comment URLs?
Add Blank Favicon?
Remove Global Styles?
Block Style Behavior?
Disable Heartbeat?
Heartbeat Frequency?
Limit Post Revisions?
Autosave Interval?
Login URL
Custom Login URL?
Disabled Behavior?
Message?
📍 Hide My WP › Settings › Cleanup › Disable XML RPC
체크하고 [Save Settings]를 누르면 아래 방문자 화면이 바뀝니다.
관리자 화면
Hide My WP
Settings was updated successfully!
Cleanup
Minify HTML
Remove comments and whitespaces from HTML (Use with cache).
Minify style
Remove theme info and other comments from stylesheet. (Require new style name)(Use with cache!).
Replace \/ URLs
Choose if you see Javascript URLs (e.g. \/wp-content\/themes)
Feed Meta
Other Meta
Default Tagline
Remove Version
Body Classes
Menu Classes
Post Classes
Clean up other
Replace in AJAX
Change Nonce
Disable XML RPC
Internal CSS
Useful to paste internal CSS code (Require New Theme Path)
Internal JS
Useful to paste internal JS code (Require New Theme Path)
로그아웃 방문자 화면 — 저장한 설정으로 요청
405
XML-RPC server accepts POST requests only.
GET 요청은 어느 설정에서나 405입니다.
200
Hello!
동작 확인용 시험 호출이라 로그인 없이 응답합니다.
200
faultCode 403 · Incorrect username or password.
비밀번호 대조가 실행됩니다. 로그인 주소를 바꿔도 같습니다.
403
본문 없음
Perfmatters가 init 단계에서 403으로 끝냅니다. PHP는 실행됩니다.
403
본문 없음
Perfmatters가 init 단계에서 403으로 끝냅니다. PHP는 실행됩니다.
403
본문 없음
비밀번호 대조 없이 403으로 끝납니다. PHP는 실행됩니다.
200
Hello!
필터 방식이라 로그인이 필요 없는 호출은 그대로 응답합니다.
405
faultCode 405 · XML-RPC services are disabled on this site.
로그인이 필요한 호출만 거부됩니다.

3. 웹 서버에서 차단: Nginx·Apache

Nginx와 Apache 어느 쪽이든 PHP 앞에서 요청을 거부하므로, 플러그인 방식과 달리 워드프레스가 실행되지 않습니다.

# Nginx — server 블록 안, PHP 처리 location 보다 위에
location = /xmlrpc.php {
    deny all;
}

이 location 블록은 PHP 처리 location보다 위에 두며, [xmlrpc.php]와 정확히 일치하는 요청을 Nginx가 바로 거부합니다. 넣은 뒤에는 설정을 점검하고 다시 읽어야 반영됩니다.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
systemctl reload nginx

다시 읽은 뒤부터 GET과 POST가 PHP까지 가지 않고 403으로 끝나며, 응답 본문은 Nginx 기본 403 페이지 153바이트이고 응답까지 0.02초입니다.

# Apache — 사이트 루트 .htaccess (Apache 2.4)
<Files xmlrpc.php>
    Require all denied
</Files>

Apache만 사용하는 서버는 사이트 루트의 .htaccess에 위 Files 지시어를 넣으면 바로 적용되며, Apache 기본 403 페이지(199바이트)가 같은 0.02초에 돌아옵니다.

curl -s -o /dev/null -w '%{http_code}' -X POST https://example.com/xmlrpc.php -d '<methodCall><methodName>demo.sayHello</methodName></methodCall>'
403

위 명령은 시험용 호출 demo.sayHello를 POST로 보내 응답 코드를 확인하며, 웹 서버에서 차단한 뒤에는 403이 돌아옵니다. [-o /dev/null]과 [-w] 옵션을 빼고 보내면 본문이 보이는데, [Hello!]가 오면 열린 상태이고, 필터로만 끈 사이트도 같은 응답이 오므로 로그인 호출까지 보내야 405를 확인할 수 있습니다.

5️⃣ 끄면 안 되는 경우와 대안

웹 서버에서 통째로 막는 방법은 효과가 가장 크지만, Jetpack으로 WordPress.com과 연결한 사이트에는 맞지 않습니다. Jetpack은 XML-RPC 연결에 의존하며, WP Engine처럼 XML-RPC를 기본 차단하는 호스팅에서는 Jetpack 쪽 안내에 따라 예외를 열어야 연결됩니다. 핑백을 받으려는 사이트도 마찬가지입니다.

이런 사이트는 Jetpack이 공개하는 IP 목록(jetpack.com/ips-v4.txt)만 허용하고 나머지를 거부하는 방식으로 좁힙니다. Nginx의 location 블록 안에 allow 줄을 IP 대역만큼 넣고 마지막에 deny all을 두면 됩니다.

완전히 막을 수 없다면 로그인하지 않은 요청에 분당 횟수 제한을 거는 방법이 남습니다. 설정은 wp-admin 보안 글의 Nginx 속도 제한 항목과 같으며, 로그인 쿠키가 없는 요청만 세므로 로그인한 관리자 작업에는 영향이 없습니다.

🔢 FAQ & 추천 콘텐츠

삭제해도 워드프레스 코어를 업데이트하면 패키지에 든 파일이 그대로 다시 복사되므로 다음 업데이트 때 복원됩니다. 파일을 삭제하는 대신 웹 서버에서 그 주소를 차단하거나 필터로 비활성화하는 쪽이 업데이트 뒤에도 유지됩니다.

REST API는 [wp-json] 주소로 들어오는 별개의 입구라서 XML-RPC를 비활성화해도 그대로 열려 있습니다. 블록 편집기가 이 입구를 사용하므로 완전히 비활성화하지 않고 로그아웃 상태의 요청만 막는 방식이 맞습니다.

확인하지 않고 보냅니다. 워드프레스는 모든 사이트에서 동일한 경로에 이 파일이 있으므로, 스캐너는 주소만 바꿔 가며 POST를 보냅니다. 기본 상태의 워드프레스는 페이지 head의 [EditURI] 링크와 핑백을 받는 글의 [X-Pingback] 헤더로 xmlrpc.php 주소를 스스로 노출합니다.

🛡️ 워드프레스 보안 추천 콘텐츠 글 8 · 바깥 글 2
🗂️ 워드프레스 보안
📋 wp-admin 보안 📄 무차별 대입 9가지 📄 Hide My WP 📄 보안 플러그인 Best 5
📄 XML-RPC 비활성화 📄 REST API 📄 핑백·트랙백 📄 wp-config.php 보안
📡 나나코 재팬 xmlrpc.php 대처법 📡 サイトの主治医 xmlrpc.php 무효화·확인
검색 결과가 없습니다.

ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.