24시간 안에 봇이 온다 — 도메인 공개 전 보안 P0

작성자

카테고리:

This post is written in Korean. Most browsers (Chrome, Edge) can translate it automatically — look for a translate icon in the address bar, or right-click the page and choose “Translate to English.”

셀프호스팅 구축기 8편. 도메인 띄우기 전에 반드시 끝내야 하는 25분.

← 이전 편: 7편 — 이름이 어렵다 (사이트명 정하기)
→ 다음 편: 9편 — 보이지 않는 다리: Cloudflare Tunnel


TL;DR

  • WordPress 도메인 공개 = 24시간 안에 brute force 봇이 옴. 통계적 사실
  • 25분 작업으로 99% 차단: ① 사용자명 admin 회피 ② xmlrpc 차단 ③ wp-login 슬러그 변경
  • 이 셋이 보안 P0. 도메인 띄우기 전에 끝낸다
  • Wordfence·2FA는 P1 (도메인 띄운 후 추가)

1. 첫 24시간의 진실

WordPress 사이트가 인터넷에 노출되면 첫 24시간 안에:

공격 빈도 대상
/wp-login.php brute force 시간당 수천 회 관리자 비번
/xmlrpc.php pingback amp 끊임없음 DDoS 증폭
알려진 플러그인 취약점 스캔 끊임없음 옛 버전 플러그인
SQL injection 시도 자동 봇 ?id=1 OR 1=1 URL
User enum (?author=1) 자동 봇 사용자명 알아내기

이걸 막을 게 아니라 표면 자체를 없애는 게 P0.


2. P0 — 보안 3종 셋업

P0 보안 3종: 봇이 두드리는 문과 막는 법 세 칸으로 나뉜 그림. 첫째 칸: 봇이 admin 사용자명으로 비번을 대입하는 brute force에 대해 P0 조치 1번 사용자명 admin 회피를 하면, 사이트에 admin 계정이 없어 대입 시도가 헛걸음이 된다. 둘째 칸: 봇이 POST /xmlrpc.php로 요청 한 번에 비번 1000개를 시도하는 증폭 공격에 대해 P0 조치 2번 mu-plugin으로 xmlrpc.php를 차단하면 403으로 즉시 차단되어 amplification이 불가능하다. 셋째 칸: 봇이 모든 WordPress 공통 로그인 URL인 GET /wp-login.php를 치는 것에 대해 P0 조치 3번 wps-hide-login 플러그인으로 로그인 슬러그를 바꾸면 301로 가짜 URL로 보내지고 /wp-admin/은 404가 된다. 아래 메모: ?author=1로 사용자명을 알아내는 시도는 Rank Math의 Disable Author Archives가 자동 차단한다. P0 3종: 봇이 먼저 두드리는 문 세 곳 도메인 공개 전에 끝낸다. 공격을 막는 게 아니라 표면 자체를 없앤다. 봇의 시도 admin 으로 비번 대입 brute force 1순위 타겟 봇의 시도 POST /xmlrpc.php 요청 1번에 비번 1000개 시도 봇의 시도 GET /wp-login.php 모든 WordPress 공통 로그인 URL P0 조치 ① 사용자명 admin 회피 설치 마법사에서 admin 입력 금지 이미 있으면 새 관리자 만들고 삭제 P0 조치 ② xmlrpc.php 차단 mu-plugin으로 강제 실행 xmlrpc_enabled → false P0 조치 ③ wp-login 슬러그 변경 wps-hide-login 플러그인 로그인 주소를 비밀 슬러그로 봇이 받는 응답 admin 계정 없음 대입 시도가 헛걸음 봇이 받는 응답 403 즉시 차단 amplification 불가 봇이 받는 응답 301 → 가짜 URL /wp-admin/ 은 404 ?author=1 로 사용자명을 알아내는 시도는 Rank Math의 Disable Author Archives가 자동 차단 (6장)
그림 1. P0 3종. 봇이 먼저 두드리는 세 곳을 도메인 공개 전에 없애 두면, 봇이 받는 응답은 헛걸음, 403, 가짜 URL뿐이다.

3. ① 사용자명 admin 회피

WordPress 설치 마법사가 첫 사용자 만들 때 admin이라고 입력하지 마세요. 봇 brute force 1순위 타겟.

좋은 예: jamjam, sailor904, 본인 닉
나쁜 예: admin, administrator, root, wpadmin

이미 admin으로 만들었으면 wp-cli로 새 사용자 생성 후 admin 권한 박탈 또는 삭제:

wp user create newname [email protected] --role=administrator --user_pass=$(openssl rand -base64 24) --allow-root
wp user delete admin --reassign=newname --allow-root

4. ② xmlrpc.php 차단 — mu-plugin

/xmlrpc.php는 WordPress 옛 API. 거의 안 쓰임 (Jetpack 사용자만). 봇이 brute force amplification (한 번 요청으로 비번 1000개 시도)에 악용.

/var/www/html/wp-content/mu-plugins/disable-xmlrpc.php:

<?php
/**
 * Plugin Name: Disable XML-RPC
 * Description: Block xmlrpc.php to reduce attack surface.
 */
if (!defined('ABSPATH')) exit;

add_filter('xmlrpc_enabled', '__return_false');
add_filter('wp_headers', function ($headers) {
    unset($headers['X-Pingback']);
    return $headers;
});
add_filter('xmlrpc_methods', function ($methods) {
    unset($methods['pingback.ping']);
    unset($methods['pingback.extensions.getPingbacks']);
    return $methods;
});
add_action('init', function () {
    $uri = $_SERVER['REQUEST_URI'] ?? '';
    if (stripos($uri, '/xmlrpc.php') !== false) {
        status_header(403);
        exit('xmlrpc disabled');
    }
});

검증:

curl -I http://localhost:8090/xmlrpc.php
# HTTP/1.1 403  ← 성공

5. ③ wp-login 슬러그 변경

/wp-login.php는 모든 WordPress 사이트가 똑같이 갖는 로그인 URL. 봇이 처음 들어와서 자동으로 칠 URL. 이걸 다른 슬러그로 숨김.

플러그인 wps-hide-login 설치:

wp plugin install wps-hide-login --activate --allow-root
wp option update whl_page starport --allow-root

starport는 주인장이 정한 비밀 슬러그. 추측 어려운 단어 + 본인 기억하기 쉬운 거. 예: byeolgorae-gate, secret-door-2026, starport.

검증:

curl -I -L http://localhost:8090/wp-login.php
# 301 redirect → 가짜 URL (봇 헛걸음)

curl -I -L http://localhost:8090/wp-admin/
# 404 (로그아웃 상태에선 admin 페이지 자체가 없는 척)

curl -I -L http://localhost:8090/starport/
# 200 (주인장만 아는 로그인 페이지)

⚠ 주인장이 슬러그 잊으면 본인도 못 들어옴. 즐겨찾기·메모 필수.


6. 결과 — 봇 입장에서

공격 차단 후 응답
GET /wp-login.php 301 → 가짜 URL → 봇이 거기서 시도 → 영원히 실패
POST /xmlrpc.php 403 즉시 차단. amplification 불가
GET /wp-admin/ 404. 관리 페이지 자체가 없는 척
사용자명 brute force admin 시도 → 우리 사이트엔 admin 없음
?author=1 user enum Rank Math가 자동 차단 (Disable Author Archives)

봇이 들이는 자원 = 주인장 사이트에서 얻는 게 0.


7. P0 vs P1 vs P2 — 우선순위

단계 작업 시점
P0 (필수, 도메인 공개 전) 사용자명·xmlrpc·wp-login 슬러그 이번 25분
P1 (도메인 띄운 직후) Wordfence 위자드 + 2FA 주인장 GUI 작업
P2 (월 1회) 플러그인 보안 업데이트 + WPA(취약점 스캔) 운영 단계
도메인 공개를 기준으로 본 P0, P1, P2 순서 왼쪽에서 오른쪽으로 흐르는 시간선. 도메인 공개 전 구간에 P0 필수 작업(이번 25분: 사용자명, xmlrpc, wp-login 슬러그)이 있다. 가운데에 도메인 공개 시점이 있고, 공개 후 24시간 안에 봇이 도착해 wp-login brute force를 시작한다. 공개 직후에는 P1(Wordfence 위자드와 2FA)을 한다. 오른쪽 운영 단계에서는 매월 P2(플러그인 보안 업데이트와 WPA 취약점 스캔)를 반복한다. P0 없이 공개하면 로그에 brute force 시도가 쌓이고 CPU를 잡아먹는다. 간격은 실제 시간에 비례하지 않는다. 도메인 공개를 기준으로 본 순서 간격은 시간 비례 아님 공개 전 도메인 공개 봇 도착 wp-login brute force 시작 운영 단계 24시간 안 매월 P0 필수 도메인 공개 전, 이번 25분 사용자명, xmlrpc, wp-login 슬러그 P1 도메인 띄운 직후 Wordfence 위자드 + 2FA P2 월 1회 플러그인 보안 업데이트 + WPA 취약점 스캔 P0 없이 공개하면: 봇이 24시간 안에 brute force를 시작하고, 로그에 시도가 쌓이며 CPU를 잡아먹는다.
그림 2. 도메인 공개를 기준으로 한 순서. P0는 공개 전에, P1은 공개 직후에, P2는 운영하면서 매달 한다.

P0 안 끝내고 도메인 띄우면 — 봇이 24시간 안에 와서 brute force 시작. 셋업 안 됐어도 어차피 못 뚫지만, 로그에 brute force 시도가 쌓이고 미니PC CPU 잡아먹음. 미리 막는 게 정신 위생.


8. 함정

함정 1. mu-plugin 자동 활성

mu-plugins는 일반 플러그인 위에서 강제 실행 (mu = Must Use). 따라서 xmlrpc 차단처럼 절대 비활성되면 안 되는 보안 정책은 mu-plugin이 맞는 곳.

함정 2. WPS Hide Login slug 잊기

whl_page 옵션을 DB에 직접 박아두기 때문에, 주인장이 슬러그 잊으면 본인도 못 들어옴. 복구 방법: wp option get whl_page --allow-root (미니PC SSH로) 또는 mu-plugin 임시 비활성.

함정 3. 인증 후 자동 우회

WPS Hide Login은 슬러그를 모르는 사람만 차단. 로그인된 세션은 그대로 /wp-admin/ 사용. 주인장이 한 번 로그인하면 그 이후 30분 동안 admin 페이지 자유.

함정 4. 로그아웃 시 새 슬러그로 진입

주인장이 로그아웃하면 다음 로그인은 /starport로. 즐겨찾기 갱신 필수.


FAQ

Q. 이미 도메인 공개해버렸는데 P0 안 했으면?
지금 즉시 cloudflared 끄거나 Tailscale Funnel 해제 → P0 셋업 → 다시 공개. 5분.

Q. Wordfence 위자드(P1)는 왜 P0 아닌가?
P0는 표면 자체를 없애는 것. Wordfence는 표면이 있는 상태에서 공격을 탐지·차단. 보완재.

Q. 슬러그를 /admin 으로 바꿔도 되나?
/admin도 봇이 시도하는 흔한 슬러그. 추천 X. 본인만 떠올릴 수 있는 + 추측 어려운 단어.

Q. 2FA 없어도 P0면 충분한가?
충분 + 충분. 2FA는 비번 노출됐을 때 마지막 방패. P0 + 2FA = 사실상 무적.

Q. xmlrpc 차단하면 Jetpack 못 쓰나?
Jetpack 일부 기능 X. Jetpack 자체가 없으면 무관. 우리 별고래는 Jetpack 안 씀.


다음 편 예고

9편 — 보이지 않는 다리: Cloudflare Tunnel. 드디어 도메인을 미니PC에 연결. 공유기 포트 안 열고, 미니PC IP 안 들키고, WAF·DDoS·CDN까지 무료로.


한 줄 정리

WordPress 도메인 공개 = 24시간 안에 봇이 옴. 25분 P0 셋업(사용자명·xmlrpc·wp-login 슬러그)으로 99% 차단. 도메인 띄우기 전에 끝낸다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다