SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor

구독 폭탄 공격 방지 및 이메일 인증 보안 설정 방법

구독 폭탄 공격은 타인의 이메일로 수많은 인증 메일을 보내 중요 알림을 가리는 수법입니다. Confirmed opt-in 설정과 IP 기반 속도 제한을 적용하여 귀하의 서버가 악용되는 것을 방지하고 이메일 발송 시스템의 보안을 강화하는 구체적인 대응책을 확인하십시오.

구독 폭탄(Subscription bombing)이란 무엇입니까?

구독 폭탄은 타인의 받은 편지함을 마비시키기 위해 귀하의 가입 양식을 악용하는 공격입니다. 공격자는 피해자의 이메일 주소 하나를 확보한 뒤, 짧은 시간 안에 수백 또는 수천 개의 보호되지 않은 웹사이트 가입 양식에 해당 주소를 입력합니다. 각 사이트는 해당 주소로 환영 메시지나 확인 메일을 발송합니다. 이렇게 쏟아지는 메시지들은 피해자가 실제로 확인해야 할 중요한 메일을 보이지 않게 만듭니다.

이 공격의 표적은 해당 이메일 계정의 소유자입니다. 받은 편지함이 구독 확인 메일로 가득 차는 동안, 공격자는 피해자의 신용카드로 결제를 진행하거나 계정 비밀번호를 재설정합니다. 은행에서 보내는 부정 사용 알림 메일도 도착하지만, 같은 시간대에 쏟아진 2,000여 개의 다른 메시지들에 파묻혀 제때 확인하지 못하게 됩니다.

귀하의 서버는 이 공격을 수행하는 도구로 사용됩니다. 서버 자체에 결함이 있는 것은 아니며, 귀하의 계정이 탈취된 것도 아닙니다. 누군가 공개된 양식에 이메일 주소를 입력했고, 귀하의 소프트웨어는 설계된 대로 해당 주소로 메일을 발송했을 뿐입니다. 이것이 바로 이 공격을 감지하기 어려운 이유입니다. 침입 자체가 발생하지 않았으므로 로그에는 어떠한 침입 흔적도 남지 않습니다.

공격이 서버 측에서 나타나는 형태

공격은 크게 두 가지 형태로 나타납니다.

소란스러운 형태는 급격한 요청 폭주입니다. 수백 개의 POST 요청이 몇 분 안에 하나의 폼으로 쏟아집니다. 이때 수많은 서로 다른 소스 IP 주소에서 이전에 메일을 보낸 적 없는 도메인의 주소들을 전송합니다. 이 형태는 로그를 확인하면 쉽게 식별할 수 있습니다.

조용한 형태는 놓치기 쉬운 유형입니다. 공격자는 수천 개의 취약한 폼 목록을 가지고 있으므로, 귀하의 폼에는 시간당 한두 건의 제출만 발생합니다. Jye Cusch는 이와 정확히 일치하는 공격 형태를 자신이 운영하는 사이트에서 겪었다고 설명했습니다. 트래픽 급증은 없었지만, 서비스 이용자의 활동 시간대와 맞지 않는 시간에 꾸준히 가입 요청이 들어왔습니다. 개별 폼만 보면 아무런 문제가 없어 보입니다. 공격자가 보유한 모든 폼에서 발생하는 피해를 합산해야 비로소 전체 규모가 드러납니다.

두 형태 모두 공격 이후에는 동일한 특징을 보입니다. 그 이후 아무런 반응이 없습니다. 해당 주소들은 메일 수신 확인을 하지 않습니다. 메시지를 열어보지도 않고 링크를 클릭하지도 않습니다. 이중 옵트인(confirmed opt-in) 목록에서 해당 주소들은 영원히 unconfirmed 상태로 머물게 되며, 이 데이터가 쌓이는 것이 공격을 입증하는 가장 확실한 증거입니다.

먼저 액세스 로그에서 분당 제출 건수를 세는 것부터 시작하십시오.

sudo awk '/POST \/subscription\/form/ {print substr($4, 2, 17)}' \
  /var/log/nginx/access.log | uniq -c | sort -rn | head

기본 combined 로그 형식에서 $4는 대괄호로 묶인 타임스탬프입니다. 따라서 이 명령은 분당 요청 수를 계산하여 가장 높은 순서대로 출력합니다. 하루에 4건의 가입이 들어오던 폼에서 1분 만에 60건이 발생했다면, 이는 정상적인 상황이 아닙니다.

확인된 옵트인: 가장 효과적인 방어 수단

확인된 옵트인(Confirmed opt-in)은 흔히 이중 옵트인(double opt-in)이라고도 불리며, 해당 주소로 발송된 메시지의 링크를 사용자가 클릭하기 전까지는 구독자로 간주하지 않는 방식을 의미합니다. 이 기능을 활성화하면 제출된 주소 하나당 정확히 하나의 메시지만 발송됩니다. 확인을 거치지 않은 주소는 목록에 추가되지 않으므로, 캠페인 메일이나 환영 메시지를 받지 않습니다.

자체 호스팅 뉴스레터 서버인 listmonk에서는 이를 목록별 설정으로 관리합니다. 즉, 각 목록은 단일 옵트인 또는 이중 옵트인으로 설정할 수 있습니다. 문서에서는 이 차이를 명확히 설명합니다. 이중 옵트인 목록의 구독자는 "수신한 확인 이메일의 링크를 클릭하여 구독을 명시적으로 승인"해야 합니다. 그전까지는 캠페인 메시지를 받지 않습니다. 구독자는 unconfirmed 상태로 대기하다가 클릭 시 confirmed 상태로 이동하며, 옵트인 목록에서 confirmed 상태인 구독자만이 캠페인 메일을 받게 됩니다.

이 설정이 가져오는 이점을 정확히 이해해야 합니다. 확인된 옵트인이 스팸 발송 기여도를 0으로 만들지는 않습니다. 다만 주소당 메시지 발송 횟수를 1회로 제한할 뿐입니다. 피해자는 여전히 그 메시지 하나를 받게 되며, 천 개의 사이트에서 각각 메시지를 하나씩 보낸다면 그것만으로도 전체 공격이 성립합니다. 확인된 옵트인이 제거하는 것은 그 이후의 모든 과정입니다. 즉, 목록을 깨끗하게 유지할 수 있으며, 첫 번째 메시지를 요청하지 않은 사람에게 두 번째 메시지를 보내는 일을 방지합니다.

중요하지만 간과하기 쉬운 설정이 두 가지 더 있습니다. 첫째, 확인 메일 재발송 횟수를 제한하십시오. 동일한 주소를 반복해서 제출할 때마다 확인 이메일이 발송된다면, 공격자는 천 개의 폼을 이용할 필요 없이 귀하의 폼 하나만으로 천 개의 메시지를 보낼 수 있습니다. 이미 해당 목록에서 unconfirmed 상태인 주소에는 최소 하루 동안 추가 메일을 보내지 않아야 합니다. 둘째, 확인되지 않은 행을 주기적으로 삭제하십시오. 30일 동안 확인하지 않은 주소는 대기 중인 구독자가 아닙니다. 이를 계속 보관하면 나중에 실수로 메일이 발송될 가능성만 남게 됩니다.

리버스 프록시에서 가입 폼 속도 제한하기

애플리케이션 내부가 아닌 프록시 앞단에서 제한을 설정하십시오. 프록시에서 차단된 요청은 데이터베이스 연결을 생성하지 않으며 SMTP(simple mail transfer protocol) 통신도 시작하지 않습니다. 애플리케이션 내부의 제한은 이미 워커 프로세스와 쿼리 비용을 소모한 뒤에 작동하며, 많은 스택에서 악용 방지 검사가 실행되기 전에 메시지가 큐에 쌓이기도 합니다. 프록시 제한은 애플리케이션을 업그레이드해도 유지되는데, 이는 교체되는 코드 내부에 존재하지 않기 때문입니다.

아래 예시는 nginx 기준입니다. 이 개념은 애플리케이션 앞단에 운영 중인 리버스 프록시 종류에 관계없이 적용할 수 있으며, 지시어 이름만 다를 뿐입니다.

이 설정을 http 블록 내, /etc/nginx/conf.d/signup-limit.conf와 같은 파일에 추가하십시오:

map $request_method $signup_key {
    POST    $binary_remote_addr;
    default "";
}

limit_req_zone $signup_key zone=signup:10m rate=2r/m;
limit_req_status 429;
limit_req_log_level warn;

map가 실제 작업을 수행합니다. nginx는 키가 빈 문자열인 요청은 카운트하지 않으므로, POST 요청만 존(zone)에 진입합니다. 가입 페이지를 여러 번 불러오는 사용자는 아무런 비용을 소모하지 않습니다. 이 맵이 없다면 페이지를 두 번 새로고침한 것만으로도 가입 버튼을 누르기도 전에 자신의 할당량을 모두 소진하게 됩니다.

$binary_remote_addr는 압축된 형태의 클라이언트 주소이며, 이 때문에 10 메가바이트 존에 약 160,000개의 주소를 저장할 수 있습니다. rate=2r/m은 30초당 1회의 제출을 허용합니다. limit_req_status 429는 nginx의 기본값인 503 대신 HTTP 429 Too Many Requests를 반환합니다. 이는 더 정확한 상태 코드이며 클라이언트 라이브러리가 기대하는 값이기도 합니다.

그다음, 사이트의 server 블록에 다음을 추가하십시오:

location = /subscription/form {
    limit_req zone=signup burst=3 nodelay;
    proxy_pass http://127.0.0.1:9000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

burst=3 nodelay는 버튼을 더블 클릭한 사용자의 요청은 통과시키되, 네 번째 요청부터는 큐에 넣지 않고 즉시 거부합니다.

sudo nginx -t && sudo systemctl reload nginx

nginx -tconfiguration file /etc/nginx/nginx.conf test is successful을 출력해야 합니다. 이제 폼을 빠르게 5번 제출하고 에러 로그를 확인하십시오:

sudo tail -f /var/log/nginx/error.log

차단된 요청은 한 줄의 로그를 남기며, 찾으려는 문자열은 다음과 같습니다:

2026/08/13 09:14:22 [warn] 812#812: *4412 limiting requests, excess: 3.400 by zone "signup", client: 203.0.113.10, server: news.example.com, request: "POST /subscription/form HTTP/1.1", host: "news.example.com"

로그가 전혀 없다면 제한이 적용되지 않은 것입니다. 흔한 원인은 limit_req이 요청이 도달하지 않는 location 블록에 위치한 경우이므로, curl -si -X POST https://news.example.com/subscription/form를 연속으로 몇 번 실행하여 429이 반환되는지 확인하십시오.

IP 기반 제한을 사용하기 전에 알아두어야 할 두 가지 함정이 있습니다.

CDN이나 다른 프록시 뒤에 있는 경우, $binary_remote_addr은 해당 프록시가 됩니다. 모든 방문자가 하나의 버킷에 담기므로, 매 분마다 첫 몇 번의 제출만으로 다른 모든 사용자가 차단됩니다. 이를 해결하려면 real IP 모듈을 사용하십시오. CDN이 공개한 각 대역(Cloudflare의 경우 cloudflare.com/ips에서 확인 가능)에 대해 set_real_ip_from를 설정하고 real_ip_header CF-Connecting-IP을 사용하십시오. 액세스 로그에서 $remote_addr를 확인하여 CDN 주소가 아닌 실제 방문자의 주소가 기록되는지 확인하면 수정이 완료된 것입니다.

IPv6 환경에서는 주소별 제한이 약화됩니다. $binary_remote_addr는 전체 /128을 유지하는데, 일반적인 IPv6 할당 단위는 /64 이상입니다. 이는 공격자가 소진하기에는 너무 많은 주소이며, 각 주소마다 별도의 할당량을 가집니다. 엔드포인트 자체에 상한선을 두는 두 번째 존을 추가하고 상수를 키로 설정하십시오. 이렇게 하면 소스 주소가 아무리 많아도 폼 전체에 대한 속도 제한이 적용됩니다:

map $request_method $signup_total_key {
    POST    "signup";
    default "";
}

limit_req_zone $signup_total_key zone=signup_total:1m rate=30r/m;

같은 locationlimit_req zone=signup_total burst=10 nodelay;을 추가하십시오. 속도 제한은 가장 바쁜 시간대의 실제 트래픽보다 여유 있게 설정하십시오. 이는 다소 거친 제어 방식입니다. 공격 중에는 실제 가입자도 차단될 수 있기 때문입니다. 하지만 서버가 메일을 발송하게 두는 것보다는 이 방식이 올바른 선택입니다.

주소별 제한을 프록시에서 처리할 수 없는 이유

이메일 주소는 POST 본문 내부에 포함되어 전달되는데, nginx는 요청 본문을 파싱하지 않습니다. limit_req_zone가 키로 사용할 수 있는 모든 변수는 요청 라인, 헤더 또는 연결 정보에서 나옵니다. 따라서 "이 주소는 하루에 최대 1개의 인증 메일만 받을 수 있다"와 같은 규칙은 본문을 읽는 첫 번째 구성 요소인 애플리케이션 계층에서 처리해야 합니다.

$arg_email를 사용할 수 있도록 주소를 쿼리 문자열로 옮기는 방식으로 우회하지 마십시오. 그렇게 하면 모든 구독자의 주소가 평문으로 액세스 로그에 기록되며, 그 이후에 연결된 모든 로그 수집기로 전달됩니다. 이는 속도 제한을 얻는 대신 개인정보 보호 문제를 초래하는 결과가 됩니다.

한 가지 예외적인 방법은 있습니다. nginx JavaScript 모듈인 njs를 사용하면 요청 본문을 읽어 변수를 설정할 수 있으므로, 프록시 단에서 주소별 키를 생성하는 것이 가능합니다. 이는 확실한 선택지이지만, 요청 경로에 새로운 코드가 추가된다는 의미이기도 합니다. 대부분의 사이트에서는 해당 주소의 인증 대기 여부를 이미 알고 있는 데이터베이스 근처에서 주소별 제한을 처리하는 것이 적절하며, 프록시는 본연의 기능인 IP별 및 엔드포인트별 제한을 담당하는 것이 좋습니다.

제출된 텍스트를 메시지에 반복하지 마십시오

공격자가 제공한 문자열을 메시지에 포함하지 마십시오. 여기에는 두 가지 별도의 이유가 있으며, 두 경우 모두 실제 공격 사례에서 사용되었습니다.

확인 이메일에서 폼에 입력된 이름을 사용하여 수신자에게 인사말을 건넬 경우, 공격자는 이름 필드에 자신의 메시지를 작성합니다. 그러면 서버는 귀하의 도메인에서 발송된 것처럼 해당 텍스트를 피해자에게 전달하며, 귀하의 DKIM(DomainKeys Identified Mail) 키로 서명됩니다. 귀하의 사이트는 타인의 악용 사례를 전달하는 도구가 되며, 수신 측 메일 제공업체는 해당 메일에서 귀하의 도메인을 확인하게 됩니다.

두 번째 이유는 더 심각합니다. 제출된 필드를 수동으로 메일 헤더에 연결할 경우, 해당 필드에 포함된 줄 바꿈 문자는 공격자가 선택한 헤더를 추가하게 만들며, 여기에는 Bcc도 포함됩니다. 현대적인 메일 라이브러리는 헤더 값 내의 줄 바꿈을 거부합니다. 하지만 셸 스크립트에서 sendmail로 텍스트를 파이프하는 코드는 종종 이를 거부하지 않습니다.

안전한 확인 메시지에는 사이트 이름과 링크 하나, 그리고 한 문장의 설명만 포함되어야 합니다. 주소 자체는 메일 전송 에이전트가 필요한 곳인 To 헤더에만 나타나야 합니다. 이를 테스트하려면 이름 필드에 줄 바꿈과 명백한 링크를 포함하여 폼을 제출한 다음, less으로 수신된 원본 메시지를 읽어 해당 내용이 포함되지 않았는지 확인하십시오.

또한, 성공 페이지는 모든 주소에 대해 동일한 내용을 표시해야 합니다. 어떤 주소에는 "이미 구독 중입니다"라고 표시하고 다른 주소에는 "받은 편지함을 확인하십시오"라고 표시하는 페이지는, 귀하의 폼을 주소 목록을 가진 누구나 테스트할 수 있는 멤버십 확인 도구로 전락시킵니다.

어떤 봇 방지 검사를 사용해야 합니까?

효과만큼이나 접근성도 중요하게 고려해야 합니다. 이미지 선택 방식의 캡차(captcha)는 시각 장애인이 해결할 수 없으며, 음성 대체 수단은 일반적인 청력을 가진 사람에게도 어렵습니다. 정당한 사용자의 가입을 가로막는 검사는 방어 수단인 동시에 비용이 됩니다. 다음 네 가지 옵션을 권장 순서대로 시도하십시오.

브라우저 내 작업 증명(Proof of work). 브라우저가 해시를 계산하면 서버가 이를 저렴한 비용으로 검증하며, 사용자가 직접 해결할 작업은 없습니다. listmonk는 설정(Settings)의 보안(Security) 항목에서 ALTCHA를 통해 이를 제공하며, 별도의 타사 서비스가 필요하지 않습니다. 2026년 8월 기준으로 이는 listmonk가 권장하는 방식이며, 기존의 hCaptcha 옵션은 더 이상 사용되지 않습니다. 이 방식은 가장 많은 요청을 보내는 공격자에게 비용을 전가합니다.

관리형 비대화형 검사. Cloudflare Turnstile은 대부분의 방문자에게 아무것도 표시하지 않으며, 신호가 의심스러운 경우에만 검사를 수행합니다. 효과적이지만 가입 경로에 타사 서비스를 포함하게 됩니다.

허니팟(Honeypot) 필드. 사람이 볼 수 없는 텍스트 입력란을 만들어 단순한 봇이 이를 채우도록 유도합니다. 폼에서 사용하지 않는 이름을 지정하고, autocomplete="off", tabindex="-1", aria-hidden="true"을 설정하여 비밀번호 관리자가 이를 채우거나 스크린 리더가 이를 읽지 않도록 합니다. email2 또는 address과 같은 이름의 필드는 브라우저가 자동으로 채울 수 있으므로, 이 경우 실제 사용자가 거부될 수 있습니다.

<div style="position:absolute; left:-9999px;" aria-hidden="true">
  <label for="hp_ref">Leave this field empty</label>
  <input type="text" id="hp_ref" name="hp_ref" autocomplete="off" tabindex="-1">
</div>

제출 시간 검사. 페이지가 렌더링될 때 서명된 타임스탬프를 숨겨진 필드에 넣고, 2초 이내에 도착하는 제출은 거부합니다. 사람은 폼을 읽고 주소를 입력하는 데 그보다 더 많은 시간이 걸립니다. 타임스탬프에 서명하지 않으면 봇이 단순히 이전 타임스탬프를 재전송할 수 있습니다.

어떤 방식을 선택하든 반드시 확인해야 할 점은 토큰이 일회용이어야 한다는 것입니다. 스크립트가 검사를 한 번 통과한 뒤 해당 토큰을 수천 개의 주소에 재사용할 수 있다면, 그 검사는 브라우저가 한 번 실행되었다는 사실 외에는 아무것도 증명하지 못한 것입니다.

남용 신고가 접수되기 전에 문제를 파악하는 방법

호스팅 업체의 남용 관리 부서가 연락하기 전에 직접 그래프를 통해 문제를 확인해야 합니다. 다음 두 가지를 모니터링하십시오.

로그에서 소스 주소별 제출 횟수를 집계합니다.

sudo awk '/POST \/subscription\/form/ {print $1}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -rn | head -20

그런 다음 nginx가 이미 기록 중인 limiting requests 로그를 fail2ban이 읽게 하여 반복적인 공격자를 차단합니다. fail2ban은 이를 위한 필터를 기본적으로 제공합니다. /etc/fail2ban/jail.d/nginx-limit-req.local 파일을 생성하십시오.

[nginx-limit-req]
enabled  = true
filter   = nginx-limit-req
port     = http,https
logpath  = /var/log/nginx/error.log
findtime = 600
maxretry = 10
bantime  = 3600
sudo systemctl reload fail2ban
sudo fail2ban-client status nginx-limit-req

상태 출력에는 jail의 필터와 현재 실패 및 차단된 횟수가 표시됩니다. 평소에는 Currently banned: 0 값이 0인 것이 정상입니다. 만약 jail이 전혀 나타나지 않는다면 fail2ban이 파일을 불러오지 못한 것이며, sudo fail2ban-client -d | grep nginx-limit-req 명령을 통해 실제로 파싱된 설정을 확인할 수 있습니다. 기본 제공 필터는 모든 limit_req 영역과 일치합니다. /etc/fail2ban/filter.d/nginx-limit-req.local 파일의 [Definition] 섹션에 ngx_limit_req_zones = signup 설정을 추가하여 가입 영역으로 범위를 좁히십시오. jail 파일 구조와 차단 명령에 대한 자세한 내용은 Ubuntu 24.04용 fail2ban 가이드에서 확인할 수 있습니다.

두 번째 지표는 비율이며 별도의 소프트웨어가 필요하지 않습니다. 제출 건수를 확인 건수로 나눈 값입니다. 정상적인 목록이라면 주소를 제출한 사람 대부분이 링크를 클릭하며, 보통 절반 이상이 클릭합니다. 제출 건수는 증가하는데 이 비율이 급락한다면 서비스가 악용되고 있는 것입니다. 기존 보고서 일정에 맞춰 지난 1시간 동안 생성된 unconfirmed 구독자 수와 confirmed 구독자 수를 비교하십시오.

비용 발생: 발신자 평판과 차단 목록

이 단계에서 단순한 성가심은 실제 비용 문제로 바뀝니다.

메일 폭탄에 사용되는 주소 목록은 무작위로 수집된 것이며, 이러한 수집된 목록에는 스팸 트랩(spamtrap)이 포함되어 있습니다. 스팸 트랩은 그 어떤 서비스에도 가입한 적이 없는 주소로, 허가 없이 메일을 보내는 발신자를 적발하기 위해 공개된 주소입니다. 귀하의 확인 메일이 이러한 주소에 도달하면, 일부 차단 목록 운영자는 이를 근거로 즉시 차단을 수행합니다.

메일을 요청한 적 없는 수신자는 구독 취소 버튼을 누르지 않습니다. 대신 "스팸 신고" 버튼을 누릅니다. 2024년 2월부터 시행된 Google의 대량 발신자 규칙에 따르면, Gmail로 하루 5,000건 이상의 메일을 보내는 발신자는 Postmaster Tools의 스팸 신고율을 0.3% 미만으로 유지해야 합니다. 소규모 발신자에게는 이 수치가 직접 적용되지 않더라도, 동일한 신고 신호가 필터링 알고리즘에 반영되어 귀하의 메일이 스팸 편지함으로 분류되게 만듭니다. 메일 폭탄에 포함된 가짜 주소들은 하드 바운스(hard bounce)를 발생시키며, 높은 하드 바운스율은 모든 대형 메일 서비스 제공업체에서 발신자 평판을 떨어뜨리는 요인이 됩니다.

만약 mailcow를 사용하여 VPS에서 직접 메일 서버를 운영 중이라면, 차단 목록 등재는 귀하의 IP 주소와 도메인에 직접적인 타격을 줍니다. Spamhaus와 같은 운영자에게 차단 해제를 요청하려면 양식을 작성하고 기다려야 하며, 그동안 청구서나 비밀번호 재설정 메일조차 발송되지 않습니다. 공유 메일 서비스를 이용 중이라면, 서비스 제공업체는 귀하의 해명보다 계정 정지를 먼저 시행할 것입니다. 귀하의 트래픽이 해당 IP를 공유하는 다른 모든 발신자에게 위험 요소가 되기 때문입니다.

이러한 위험에 비하면 예방 작업은 매우 간단합니다. 오늘 바로 확인된 옵트인(confirmed opt-in)을 활성화하십시오. 목록당 설정 하나만 변경하면 됩니다. 그다음 프록시 속도 제한(rate limit)을 추가하십시오. 설정 파일 하나를 수정하고 다시 불러오기만 하면 됩니다. 봇 차단과 알림 설정은 이번 주 내로 마무리할 수 있습니다.

FAQ

이중 옵트인(double opt-in)으로 구독 폭탄(subscription bombing)을 막을 수 있습니까?

이중 옵트인은 메일링 리스트가 오염되는 것을 방지하며, 제출된 주소당 발송되는 메시지를 단 한 통으로 제한합니다. 이는 여러분이 취할 수 있는 가장 효과적인 대응책입니다. 하지만 공격자가 수천 개의 사이트에서 각각 한 통씩 메시지를 보내는 방식이므로, 피해자의 메일함이 가득 차는 것까지 막을 수는 없습니다. 프록시에서 IP별로 rate limit을 설정하고 확인 메일 재전송 횟수를 제한하여, 동일한 주소가 두 번 제출되어도 두 번째 메시지가 발송되지 않도록 조치하십시오.

실제 구독자가 몰리는 것과 구독 폭탄 공격을 어떻게 구분합니까?

제출 이후의 과정을 확인하십시오. 실제 구독자는 확인 절차를 거치며, 보통 몇 시간 내에 확인을 완료합니다. 반면 구독 폭탄 공격은 확인하지도, 열어보지도, 클릭하지도 않는 주소들만 쌓이게 만듭니다. 또한 제출 패턴도 비정상적입니다. 평소 본 적 없는 소스 주소들이나 평소 발송하지 않던 도메인들이 포함되며, 구독자의 활동 시간대와 관계없이 하루 종일 고르게 유입되는 특징이 있습니다.

제출된 주소들을 삭제해야 합니까?

그렇습니다. 약 30일 이상 확인되지 않은 레코드들은 수동이 아닌 정기적인 스케줄에 따라 삭제하십시오. 해당 주소들로 사과 메일이나 "본인이 맞습니까?"와 같은 메시지를 절대 보내지 마십시오. 이미 수많은 메일에 파묻힌 사람에게 또 다른 원치 않는 메시지를 보내는 꼴이 되기 때문입니다. 만약 그 주소들 중에 스팸 트랩(spamtraps)이 포함되어 있다면, 후속 메일을 보내는 행위가 바로 차단 리스트 운영자가 기다리는 확인 사살이 됩니다.

rate limiting을 적용하면 실제 구독자가 거부되지 않습니까?

30초당 1회 제출, 최대 3회까지 허용하는 IP별 제한은 폼을 한 번 작성하는 일반 사용자에게는 아무런 영향을 주지 않습니다. 다만 단일 NAT(network address translation) 게이트웨이를 사용하는 사무실처럼 여러 사람이 같은 IP를 공유하거나, 프록시가 방문자의 IP 대신 CDN의 주소를 인식하는 경우에는 문제가 될 수 있습니다. 설정을 강화하기 전에 액세스 로그의 $remote_addr를 확인하고, 엔드포인트 제한 수치를 가장 바쁜 시간대의 실제 트래픽보다 높게 유지하십시오.

공격 이후 발송 IP가 차단 리스트에 올랐습니다. 가장 먼저 무엇을 해야 합니까?

차단 해제를 요청하기 전에 해당 IP에서의 발송을 즉시 중단하십시오. 캠페인 큐를 일시 정지하고, 폼을 수정하며, 확인되지 않은 주소들을 삭제하십시오. 차단 해제 후에도 동일한 트래픽이 계속되면 처음보다 더 빠르게 재차단됩니다. 그 후 IP 주소를 기반으로 차단 여부를 조회할 수 있는 운영자의 페이지를 찾아 차단 리스트를 확인하고, 해당 운영자의 제거 절차를 따르십시오. 대기 기간은 며칠이 소요될 수 있습니다. 이 시간을 활용하여 SPF(sender policy framework) 레코드와 DKIM 서명이 모두 정상적으로 통과하는지 확인하십시오.

#email#double-opt-in#rate-limiting#abuse#deliverability