WP 보안: wp-admin 보안 | 로그인 주소 변경·로그인 제한·XML-RPC

wp-admin 보안은 워드프레스 관리자 화면과 로그인 화면으로 들어오는 무차별 대입 공격을 막는 설정입니다. 워드프레스 사이트 여러 개를 운영하는 Nginx + Apache 구성 서버의 접근 기록을 확인한 결과, 로그인 주소를 바꾼 뒤에도 xmlrpc.php로 들어오는 자동 요청이 이어져 서버 단의 속도 제한까지 함께 적용하게 되었습니다.
1️⃣ wp-admin과 wp-login.php가 공격받는 이유
워드프레스 관리자 주소가 알려져 있다는 것이 취약점이지만 보안을 강화하여 이를 보완할 수 있습니다. 모든 워드프레스 사이트가 같은 /wp-admin/과 [wp-login.php]를 사용하며, 로그아웃한 상태로 /wp-admin/을 열면 [wp-login.php] 로그인 화면으로 이동합니다.
공격은 이 로그인 화면에 사용자명과 비밀번호를 반복해서 넣어 보는 무차별 대입으로 들어옵니다. 그래서 wp-admin 보안은 주소를 감추는 일보다 로그인 시도를 막는 일이 먼저입니다.
2️⃣ 로그인 주소 변경의 효과와 한계
보안 플러그인으로 로그인 주소를 바꾸면 기본 [wp-login.php]는 404 오류를 돌려주게 되어, 기본 주소를 그대로 두드리는 자동 공격은 로그인 화면까지 오지 못합니다. 바꾼 주소는 관리자 계정을 가진 사람에게 따로 알려야 합니다.
이 방법은 손이 적게 들지만, 바꾼 주소를 잊으면 관리자 화면에 들어갈 수 없어 FTP나 파일 관리자에서 그 플러그인 폴더 이름을 바꿔 비활성화해야 합니다. 여러 사람이 관리하는 사이트라면 주소를 한곳에 기록해 두는 편이 맞습니다.
3️⃣ 로그인 시도 제한과 2단계 인증
로그인 주소를 바꿔도 새 주소가 알려지면 비밀번호를 맞히는 시도는 그대로 이어집니다. 워드프레스 코어에는 로그인 실패 횟수 제한이 없어, 틀린 비밀번호를 몇 번 넣어도 같은 로그인 화면이 다시 열립니다.
로그인 시도 제한 플러그인은 정해진 횟수를 넘긴 IP를 일정 시간 차단하고, 2단계 인증은 비밀번호가 맞아도 휴대폰 인증 앱의 코드를 한 번 더 요구합니다. 2단계 인증을 켤 때는 휴대폰을 잃었을 때 쓸 백업 코드를 함께 보관합니다.
4️⃣ xmlrpc.php 닫기
[xmlrpc.php]는 로그인 화면을 거치지 않고 사용자명과 비밀번호를 받는 두 번째 입구이며, [system.multicall] 방식을 쓰면 요청 한 번에 여러 비밀번호를 시험할 수 있습니다.
워드프레스 사이트 여러 개를 운영하는 Nginx + Apache 구성 서버의 접근 기록을 보면, 10월 13일 0시부터 9시 50분까지 [xmlrpc.php]로 들어온 POST 요청이 2,250건이었습니다. 요청은 IP 22개에서 들어왔고, User-Agent는 Jetpack과 WordPress.com을 사칭하고 있었습니다.
워드프레스 모바일 앱이나 Jetpack을 사용하지 않는다면 Nginx 설정에서 [xmlrpc.php] 요청을 막거나 보안 플러그인의 XML-RPC 끄기 설정을 사용합니다.
# server 블록 안 — xmlrpc.php 요청 거부
location = /xmlrpc.php {
deny all;
}이 설정을 넣으면 [xmlrpc.php]로 들어오는 GET과 POST 요청이 PHP까지 가지 않고 모두 403으로 끝납니다. 보안 플러그인의 XML-RPC 끄기는 로그인이 필요한 요청만 거부하고 파일은 계속 응답하므로, PHP 실행까지 줄이려면 Nginx에서 막는 편이 맞습니다.
5️⃣ 서버에서 막기: 관리자 접근 IP 제한·속도 제한
고정 IP에서만 관리한다면 Nginx에서 [wp-login.php]와 /wp-admin/을 그 IP만 허용하는 방법이 가장 확실합니다. 집이나 사무실 IP가 자주 바뀌는 환경에는 맞지 않습니다.
/wp-admin/ 전체를 막으면 될 것 같지만, 방문자 화면의 검색이나 장바구니 같은 기능이 [admin-ajax.php]로 요청을 보내는 경우가 많아 그 파일은 열어 두어야 합니다.
# server 블록 안 — PHP 처리 location 보다 위에
location = /wp-login.php {
allow 203.0.113.10; # 관리하는 고정 IP
deny all;
# 이 아래에 PHP 처리 location 의 설정을 그대로 옮김
}지정한 IP가 아닌 곳에서 [wp-login.php]를 열면 403이 나오고, 지정한 IP에서는 로그인 화면이 열립니다. location 안에는 사이트의 PHP 처리 설정(fastcgi_pass 등)을 그대로 옮겨 넣어야 로그인 화면이 정상으로 실행됩니다.
IP를 고정할 수 없다면 로그인하지 않은 방문자의 PHP 요청에 속도 제한을 거는 방법이 있으며, 1분에 30회로 제한해 자동 요청이 서버 자원을 차지하지 못하게 한 과정은 php-fpm max_children 경고 글에 있습니다.
# http 블록 — 로그인 쿠키가 없는 요청만 IP별로 계산
map $http_cookie $php_anon_key {
default $binary_remote_addr;
"~*wordpress_logged_in" "";
}
limit_req_zone $php_anon_key zone=php_anon:10m rate=30r/m;
# PHP 처리 location 안
limit_req zone=php_anon burst=60 nodelay;
limit_req_status 429;로그인하지 않은 IP 하나가 PHP 요청을 연달아 보내면 61번째까지 처리되고 그 뒤로는 429가 반환되며, 로그인 쿠키가 있는 요청은 계산하지 않습니다. 페이지 캐시가 PHP를 거치지 않고 응답하는 구성이라면 일반 방문자의 페이지 열람은 이 제한에 걸리지 않습니다.
ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.