올해의 특가 1개월 구매 시 1개월 무료 모든 VPS와 전용 서버에, 기간에 관계없이 적용 — 12개월 결제하면 24개월 사용. 기간 2배로 받기
/ 프라이버시 호스팅 가이드 / VPS DDoS 방어: 호스트가 멈추고 7계층이 시작되는 지점
운영

VPS DDoS 공격에서 살아남기

모든 호스팅 플랜은 "DDoS 방어 포함"이라고 말하지만, 그 의미는 하나같이 좁습니다: 네트워크가 기가비트 단위로 측정되는 플러드를 흡수한다는 뜻일 뿐입니다. 실제로 소규모 사이트를 무너뜨리는 공격은 초당 요청 수로 측정되고, 공격자에게는 거의 비용이 들지 않으며, 완전히 정상적인 트래픽처럼 도착합니다. 이 가이드는 이 둘 사이에 선을 긋고, 1분 안에 자신이 어느 쪽에 있는지 판별하는 방법을 보여주며, 여러분의 몫인 쪽에서 실제로 버텨내는 방법을 다룹니다.

KYC 없음
암호화폐 결제 전용
로그 없음
DMCA 무시
전체 root 권한
NVMe SSD

DDoS 완화가 실제로 어떻게 작동하는지 사람들이 깨닫는 순간은 두 번 찾아옵니다. 첫 번째는 평온한 순간으로, 구매 시점에 "DDoS 방어 포함"이라는 기능 목록을 읽으며 그 한 문장이 모든 것을 다 커버한다고 조용히 넘겨짚을 때입니다. 두 번째는 새벽 세 시, 사이트가 다운되고 그래프가 말도 안 되는 방식으로 이상하게 나타나며, 포함되어 있다던 그 방어가 — 정확히, 그리고 설계상 — 아무 일도 하지 않고 있을 때입니다.

두 순간 모두 같은 상품과 같은 진실을 담고 있습니다: 호스팅 제공업체는 원시 트래픽 양으로 도착하는 공격을 걸러냅니다. 그 패킷이 지나가는 회선을 여러분이 아니라 제공업체가 소유하고 있기 때문입니다. 반면 평범해 보이는 요청으로 도착하는 공격은 걸러낼 수 없습니다. 네트워크의 관점에서는 그저 평범해 보이는 요청일 뿐이기 때문입니다. 그 경계선 — 호스트가 흡수해 주는 플러드와 여러분 스스로 버텨내야 하는 플러드 사이의 경계 — 이 이 가이드 전체의 주제입니다. 아래의 모든 내용은 여러분이 그 경계선의 어느 쪽에 있는지 판별하고, 각각의 경우에 무엇을 해야 하는지에 관한 것입니다.

이름은 하나, 공격은 둘

"DDoS"는 하나의 단어이지만, 결과 말고는 공통점이 거의 없는 두 가지 문제를 함께 가리킵니다. 이 둘은 서로 다른 곳에서, 서로 다른 사람에 의해, 서로 다른 도구로 저지되며, 이 둘을 혼동하는 것이야말로 그토록 많은 완화 노력이 엉뚱한 계층에 쏟아지는 이유입니다.

볼류메트릭 — 3계층과 4계층애플리케이션 — 7계층
들어오는 것SYN 플러드, 오픈 DNS·NTP·memcached 리플렉터를 이용한 UDP 증폭, ACK 플러드, 순수한 쓰레기 패킷평범한 HTTP 요청: GET 플러드, POST 플러드, 슬로로리스(slow-loris), 캐시 버스팅 쿼리 문자열
측정 단위기가비트와 초당 수백만 패킷초당 요청 수 — 흔히 수천 건에 불과함
피해를 주는 데 필요한 대역폭막대함. 이는 용량 대결임거의 필요 없음. 엔드포인트가 충분히 비싸다면 노트북 한 대로도 가능함
저지되어야 하는 위치업스트림, 제공업체 단에서. 패킷이 포트에 도달했을 때는 이미 피해가 끝난 뒤임서버 위, 여러분 자신에 의해, 또는 그 앞에서 여러분이 통제하는 프록시에 의해
서버에서 보이는 모습인터페이스가 포화되고, 패킷 카운터가 터무니없으며, CPU는 한가할 수 있음대역폭은 평범하지만 모든 워커가 바쁘고, 부하가 치솟으며, 데이터베이스 큐가 늘어남
해결하는 주체호스트의 필터링, 자동으로, 보통 몇 초 안에여러분의 설정 — 속도 제한, 캐싱, 연결 상한선

마지막 두 행을 다시 읽어 보십시오. 실질적인 요점이 거기에 있기 때문입니다. 인터페이스가 포화되어 있다면 서버에 무엇을 입력하든 도움이 되지 않습니다: 패킷은 이미 포트를 다 써 버렸고, 그것을 버릴 수 있는 유일한 주체는 업스트림 라우터를 소유한 쪽뿐입니다. 반대로 인터페이스는 조용한데 사이트는 여전히 다운되어 있다면 상황은 정반대입니다 — 호스트의 계층에서는 실제로 아무 문제도 없기 때문에 호스트 눈에는 이상이 전혀 보이지 않으며, 그 해법은 전적으로 여러분의 몫입니다.

VPS DDoS 공격에서 살아남기
볼류메트릭 플러드는 용량이 있는 업스트림에서 필터링됩니다. 그 필터를 뚫고 살아남는 것은 평범해 보이는 트래픽이며 — 이를 막는 일은 호스트가 아니라 여러분의 몫입니다.

"DDoS 방어 포함"으로 실제로 얻는 것

네트워크 계층 방어는 실재하고, 가치 있으며, 거의 항상 잘못 이해됩니다. 제공업체가 L3/L4 필터링을 광고할 때, 그것이 뜻하는 바는 그들의 네트워크가 여러분의 주소로 향하는 트래픽을 감시하다가, 플러드가 감지되면 그 트래픽을 필터링 장비로 우회시켜 악성 부분을 버리고 정상으로 보이는 부분만 전달한다는 것입니다. 이는 지원 티켓 없이 일어나며, 보통은 짧은 순간의 이상 외에는 여러분이 알아채지도 못합니다.

이 한 문장이 담당하는 일이 많으므로, 그것이 무엇을 포함하고 무엇을 포함하지 않는지 풀어볼 가치가 있습니다:

  • 혼자서는 버텨낼 수 없는 공격을 커버합니다. 1 Gbps 포트를 가진 서버에 200 Gbps 증폭 플러드가 들어오는 것은 설정의 문제가 아닙니다. 그것은 산수의 문제입니다. 업스트림 필터링이 존재하는 유일한 답입니다.
  • 애플리케이션에 대해서는 무상태입니다. 필터는 여러분의 어떤 URL이 비싼지, 어떤 방문자가 로그인했는지, 검색 엔드포인트에 대한 요청 하나가 로고 이미지 요청 하나보다 400배 더 비싸다는 것을 알지 못합니다.
  • 여러분의 고통이 아니라 임계값에 반응합니다. 탐지는 트래픽 양을 기준으로 발동됩니다. 임계값을 결코 넘지 않는 공격은, 그것이 아무리 완벽하게 사이트를 무너뜨렸다 해도 결코 탐지를 발동시키지 않습니다.
  • 극단적인 경우 잠시 널 라우팅될 수 있습니다. 모든 네트워크에는 상한선이 있습니다. 공격이 공유 인프라를 위협한다면 해당 주소가 일정 기간 차단될 수 있습니다 — 이는 표준적이고 보편적인 조치이며, 일이 벌어지는 도중이 아니라 벌어지기 전에 알아 둘 가치가 있습니다.

한 줄 요약: 여러분의 호스트는 자신의 네트워크를 보호하며, 여러분은 그 혜택을 받습니다. 호스트는 여러분의 애플리케이션을 보호하지 않으며, 그럴 방법도 없습니다. 7계층은 여러분에게 감춰 둔 유료 업그레이드가 아닙니다 — 그것은 여러분의 TLS를 종료시키지 않고서는 제공업체가 들여다볼 수 없는 계층이며, 오프쇼어 호스팅을 이용하는 사람에게 TLS 종료란 그 자체로 심각한 대가가 따르는 거래입니다.

먼저, 이것이 정말 공격인지부터 판단하십시오

DDoS로 의심되는 사건 중 상당수는 다른 무언가가 그 외투를 걸치고 있는 것이며, 그 해법은 서로 바꿔 쓸 수 없습니다. 무엇이든 속도 제한을 걸기 전에, 가짜 후보들을 배제하는 데 2분을 쓰십시오 — 여기서의 오진은 한 시간을, 때로는 진짜 사용자를 대가로 치르게 합니다.

  • 인기를 얻은 것입니다. 대형 애그리게이터에 걸린 링크 하나는 L7 플러드와 정확히 똑같아 보이는 트래픽 형태를 만들어 내지만, 리퍼러는 진짜이고 요청도 사람이 원할 만한 페이지에 대한 것입니다. 이는 원인이 반가운 용량 문제이며, 여기에 속도 제한을 거는 것은 자해입니다.
  • 크롤러가 예의를 잃은 것입니다. 공격적인 스크레이퍼와 AI 학습용 봇은 소형 서버를 손쉽게 압도할 수 있습니다. user-agent가 대개 스스로를 실토하며, 해법은 일반적인 제한이 아니라 robots.txt와 표적화된 제한입니다.
  • 여러분이 무언가를 망가뜨린 것입니다. 캐싱을 꺼 버린 배포, 폭주하는 크론 작업, 인덱스를 잃어버린 데이터베이스 — 이 모두가 "갑작스러운 부하, 뚜렷한 원인 없음"으로 나타납니다. 시점이 여러분이 가한 변경과 맞아떨어진다면, 그 변경을 의심하십시오.
  • 여러분 자신의 모니터링이 플러드인 것입니다. 드물고 민망하지만, 누구나 인정하는 것보다 훨씬 흔합니다. 백오프 없이 재시도하는 헬스 체크 루프는 정말이지 인상적인 요청률을 만들어 낼 수 있습니다.

구별하는 질문은 간단합니다: 그 트래픽이 무언가를 원하는가? 실제 부하는 — 적대적으로 보이는 실제 부하조차도 — 형태를 갖추고 있습니다. 존재하는 페이지를 두드리고, 링크를 따라가고, 에셋을 로딩하며, 그럴듯하게 퍼져 있는 네트워크에서 옵니다. 공격은 보통 그런 수고를 하지 않습니다.

서버 자체에서 공격 읽어내기

무슨 일이 벌어지고 있는지 분류하는 데 대시보드는 필요 없습니다. 순서대로 실행하는 네 개의 명령이 1분도 안 되어 어느 계층에서 싸우고 있는지 알려줍니다 — 그리고 그것을 아는 것이 이후에 할 모든 일을 결정합니다.

회선이 꽉 찼습니까? 인터페이스 카운터를 지켜보십시오. 처리량이 포트 상한선 근처에 고정되어 있다면 볼류메트릭 공격 상황이며, 여러분이 할 일은 설정 변경이 아니라 지원 티켓입니다:

  • vnstat -tr 10 — 10초간 평균 처리량으로, 포화 여부를 가장 빠르고 정직하게 읽는 방법입니다.
  • cat /proc/net/dev를 1초 간격으로 두 번 — 인터페이스별 패킷·바이트 증분을 별도 도구 없이 볼 수 있습니다.

SYN 플러드입니까? 반쯤 열린 연결이 SYN-RECV 상태로 쌓입니다. 몇 개라면 정상이지만, 수천 개라면 아닙니다:

  • ss -s — 요약 줄로, 상태별 연결 수를 한눈에 보여줍니다.
  • ss -tn state syn-recv | wc -l — 정말 중요한 그 숫자입니다.

7계층입니까? 대역폭은 별다를 게 없는데 모든 것이 느리다면, 액세스 로그에서 클라이언트별 요청 수를 세어 보십시오. 주소 하나가 수만 건을 기록했다면 아마추어이고, 10만 개의 주소가 각각 세 건씩 기록했다면 진짜입니다:

  • tail -n 100000 access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -30
  • $1 대신 $7을 넣으면 요청된 경로를 대신 순위 매길 수 있습니다. 하나의 비싼 엔드포인트가 압도적이라면, 표적과 해법의 절반을 찾은 것입니다.

실제로 고갈된 것은 무엇입니까? 로드 애버리지 자체만으로는 알려주는 것이 별로 없습니다. 여러분이 부딪힌 구체적인 상한선을 찾으십시오: PHP-FPM 자식 프로세스가 모두 바쁜지, 데이터베이스 연결이 한계에 도달했는지, 파일 디스크립터가 고갈되었는지, 아니면 워커들이 디스크를 기다리며 D 상태에 멈춰 있는지 말입니다. 사이트를 무너뜨린 것은 트래픽이 아니라 바로 그 상한선이며, 그것을 올리는 편이 무언가를 필터링하는 것보다 빠를 때가 많습니다.

확인하는 동안 이것을 기억해 두십시오: 프라이버시 중심 서비스를 운영한다면, 공격을 받는 바로 그 순간이야말로 로깅을 높여 그대로 유지하고 싶은 유혹이 가장 커지는 때입니다. 필요하다면 로깅을 높이되, 그런 다음에는 다시 낮추고 파일을 적극적으로 로테이션하십시오. 한 달치 상세 방문자 로그를 디스크에 남겨 둔 사건은 문제 하나를 더 나쁘고 더 오래가는 문제와 맞바꾼 셈입니다. 이 규율은 저희 서버 OpSec 가이드에서 다룹니다.

처음 10분

압박을 받으면 사람들은 손에 잡히는 가장 큰 레버부터 당기게 마련이며, 그 가장 큰 레버는 대개 틀린 선택입니다. 다음은 피해를 억제하는 순서로, 대략 가장 빠르고 안전한 조치부터 나열한 것입니다:

  1. 행동하기 전에 먼저 분류하십시오. 인터페이스가 포화되어 있다면 볼류메트릭이고, 인터페이스는 조용한데 워커가 바쁘다면 7계층입니다. 여기에 30초를 쓰면 엉뚱한 계층을 한 시간 동안 고치는 일을 피할 수 있습니다.
  2. 볼류메트릭이라면 즉시 티켓을 여십시오. 목적지 주소, 시작 시각, 인터페이스 카운터를 포함하십시오. 그런 다음 서버에 무언가를 입력하는 것을 멈추십시오 — 내부에서는 이것을 고칠 수 없습니다.
  3. 7계층이라면 캐싱부터 하십시오. 익명 방문자에 대해 적극적인 전체 페이지 캐싱을 켜는 것은 장애를 대수롭지 않은 일로 바꾸는 가장 빠른 단일 방법이며, 실제 트래픽에도 똑같이 도움이 되는 유일한 조치입니다.
  4. 그다음 속도 제한을 거십시오 — 표적이 된 엔드포인트를 먼저, 나머지는 그다음입니다. 보수적으로 시작하십시오. 여러분 자신의 사용자를 쫓아내는 제한은 스스로 가하는 공격의 연장일 뿐입니다.
  5. 명백한 것만 차단하십시오. 각각 10만 건씩 요청한 열두 개의 주소, 누가 봐도 가짜인 user-agent, 사용자가 전혀 없는 어느 한 국가 같은 것들입니다. 공격을 받는 와중에 정교한 규칙을 작성하고 싶은 충동은 참으십시오. 다음 달이면 그 규칙들을 기억하지 못할 것입니다.
  6. 필요하다면 의도적으로 부하를 덜어내십시오. 인증되지 않은 방문자에게 정적인 "점검 중" 페이지를 보여주는 것은 서버를 살려 두고, API를 계속 띄워 두며, 생각할 시간을 벌어 줍니다. 무엇을 희생할지는 스스로 정하는 편이 남이 대신 정하게 두는 것보다 낫습니다.
  7. 무엇을 했는지 기록해 두십시오. 추가한 모든 임시 규칙은 미래의 여러분을 위한 지뢰입니다. 도움이 된 규칙은 영구적인 것이 되고, 나머지는 내일 제거하십시오.

버텨내는 속도 제한, 그리고 누구나 저지르는 실수

속도 제한은 7계층에 대한 주된 수단이며, nginx는 진짜로 서로 다른 두 가지 문제를 해결하는 두 지시어로 이를 잘 처리합니다. limit_req는 요청 빈도를 제한합니다 — 클라이언트가 얼마나 자주 요청할 수 있는지입니다. limit_conn동시성을 제한합니다 — 한 클라이언트가 한 번에 얼마나 많은 연결을 열어 둘 수 있는지입니다. 플러드에는 첫 번째가 필요하고, 워커 풀을 고갈시키기 위해 거의 유휴 상태인 연결을 수천 개씩 붙잡고 있는 슬로로리스 공격에는 두 번째가 필요합니다. 둘 중 하나만 적용하면 문제의 절반에 대해서만 대비한 것입니다.

세 가지 세부 사항이 실제로 작동하는 제한과 장식에 불과한 제한을 가릅니다:

  • 버스트를 사용하고, nodelay를 사용하십시오. 실제 브라우저는 버스트성을 띱니다 — 페이지 조회 한 번에 거의 동시에 십여 건의 에셋 요청이 발생합니다. 여유 없는 제한은 진짜 방문자를 억제하는 반면, 임계값 바로 아래로 속도를 조절하는 공격자는 유유히 통과합니다.
  • 비싼 엔드포인트는 따로 제한하십시오. 검색 페이지, 로그인 폼, 비밀번호 재설정, 그리고 데이터베이스에 쓰기 작업을 하는 모든 엔드포인트는 정적 에셋보다 훨씬 빡빡한 예산을 받아야 합니다. 공격자는 애쓰지 않고도 이런 곳을 찾아냅니다. 바로 그런 곳이 아프기 때문입니다.
  • 503이 아니라 429를 반환하십시오. 이 상태 코드는 이것이 장애가 아니라 조절이라는 신호를 예의 바른 클라이언트와 검색 엔진에게 보냅니다 — 그리고 힘든 오후 하루가 순위 문제로 번지는 것을 막아 줍니다.

이 모든 것을 조용히 무력화시키는 실수: CDN, 로드 밸런서, 여러분 자신의 리버스 프록시 등 무엇이든 서버 앞에 자리하고 있다면, 모든 요청은 방문자의 주소가 아니라 그것의 주소에서 도착합니다. 그러면 클라이언트별 속도 제한은 인터넷 전체를 하나의 클라이언트로 취급하게 되어, 아예 아무 작동도 하지 않거나 여러분의 전체 방문자를 한꺼번에 차단하게 됩니다. 제한이 무언가를 의미하려면 먼저 real-IP 소스를 설정해야 합니다(nginx에서는 프록시의 대역을 위한 set_real_ip_from과, 프록시가 보내는 헤더를 위한 real_ip_header입니다). 이것도 프록시 자신의 대역으로 제한하십시오: 공개 인터넷에서 온 클라이언트 제공 헤더를 신뢰하면 공격자가 요청마다 새로운 신원을 위조해 여러분이 가진 모든 제한을 그대로 뚫고 지나갈 수 있습니다.

캐싱은 여러분이 배치할 가장 저렴한 완화책입니다

속도 제한은 작업을 거부합니다. 캐시는 작업이 아예 존재하지 않게 만듭니다. 익명 방문자가 보는 모든 것에 대해, 전체 페이지 캐싱은 공격 전체의 경제성을 바꿔 놓습니다: 데이터베이스 왕복과 템플릿 렌더링, PHP 워커 하나를 소모했을 요청이 마이크로초 단위로 측정되는 파일 읽기가 됩니다. 초당 400건의 동적 요청에서 무너졌던 바로 그 서버가 수만 건의 캐시된 요청을 눈치채지도 못한 채 처리하게 됩니다.

화가 난 채로 이를 켤 때 중요한 것들입니다:

  • 익명 방문자에 대해서만 캐싱하십시오. 세션 쿠키가 있으면 우회시키십시오. 로그인한 한 사용자의 페이지를 다른 사용자에게 보여주는 것은 지금 고치려던 장애보다 훨씬 나쁜 사고입니다.
  • 의도적으로 스테일 콘텐츠를 제공하십시오. nginx의 proxy_cache_use_staleupdating error timeout과 함께 사용하면, 백엔드가 힘겨워할 때 방문자가 오류 대신 약간 오래된 페이지를 받게 된다는 뜻입니다. 공격을 받는 동안 이는 멀쩡해 보이는 사이트와 죽어 보이는 사이트의 차이를 만듭니다.
  • 중복된 캐시 미스를 병합하십시오. proxy_cache_lock은 캐시되지 않은 같은 페이지에 대한 천 개의 동시 요청이 천 번이 아니라 단 한 번의 백엔드 요청을 발생시키도록 보장합니다. 이것이 없으면 캐시 버스팅 공격이 캐시를 그대로 통과해 데이터베이스에 전력으로 떨어집니다.
  • 캐시 버스팅 쿼리 문자열을 무력화하십시오. 흔한 수법은 ?와 임의의 값을 덧붙여 모든 요청을 고유한 키로 만들어 영원히 캐시 미스가 나게 하는 것입니다. 여러분의 애플리케이션이 실제로 쓰지 않는 쿼리 매개변수는 무시하도록 캐시 키를 정규화하십시오.

여기에는 마음에 새겨 둘 만한 유쾌한 비대칭이 있습니다: 캐싱에 쓰는 매 시간은 가장 좋은 날의 사이트를 더 빠르게 만들고, 운영 비용을 낮추며, 성공을 더 잘 버텨내게 해 줍니다. 아무 문제도 없을 때 배당을 지급하는 방어선은 거의 없습니다.

쓰러질지 여부를 결정하는 상한선들

대부분의 서버는 CPU가 바닥나서 죽지 않습니다. 아무도 일부러 설정하지 않은 보이지 않는 상한선에 부딪혀서 죽습니다 — 10년 전에는 말이 됐지만 이제는 아무도 쓰지 않는 하드웨어를 기준으로 잡힌 기본값 같은 것입니다. 공격을 받는 동안 실제로 가장 먼저 깨지는 것은 다음과 같습니다:

  • 애플리케이션 워커. PHP-FPM의 pm.max_children, Python 워커 수, Node 클러스터 크기입니다. 이것이 여러분 사이트의 실질적인 동시성 한계입니다. 이들이 모두 바쁘면 추가로 들어오는 방문자는 모두 대기열에 쌓이고, CPU가 아무리 한가해 보여도 사이트는 다운된 상태입니다. 메모리가 허용하는 한도까지만 올리십시오 — 스와핑은 대기열보다 나쁩니다.
  • accept 큐. net.core.somaxconn과 listen 백로그가 몇 개의 연결이 accept를 기다릴 수 있는지를 결정합니다. 백로그가 작으면 버텨낼 수 있었던 버스트가 거부된 연결로 바뀝니다.
  • SYN 쿠키. net.ipv4.tcp_syncookies는 결코 완료되지 않을 연결에 상태를 할당하지 않고도 커널이 SYN 플러드에 응답할 수 있게 해 줍니다. 최신 커널은 기본적으로 이를 활성화하지만, 그냥 가정하지 말고 확인하십시오. 비용은 전혀 들지 않으면서 가장 흔한 플러드로부터 지켜 주기 때문입니다.
  • 파일 디스크립터. 모든 연결은 디스크립터 하나입니다. 기본 nofile 한도는 여러분이 처리하려는 연결 수보다 낮은 경우가 많으며, 그 실패 양상 — 다른 모든 것이 멀쩡해 보이는데 accept만 실패하는 것 — 은 새벽 세 시에는 정말이지 혼란스럽습니다.
  • 데이터베이스 연결. 연결 풀은 늘리지 않은 채 워커 수만 늘리면 대기열이 그저 보기 더 어려운 곳으로 옮겨갈 뿐입니다. 이 두 숫자는 함께 조정해야 합니다.

이런 값들은 사건이 벌어지는 도중이 아니라 평온한 날에 조율해 두십시오. 이를 미리 알아 두는 이유는, 사이트가 쓰러졌을 때 추측하는 대신 어느 상한선에 부딪혔는지 짚어낼 수 있기 때문입니다 — 그리고 이름이 붙은 상한선은 고칠 수 있는 상한선입니다.

오리진 앞에 무언가를 두기

위의 모든 내용은 서버 위에서 일어나는 일입니다. 다음 단계는 애초에 서버가 트래픽을 직접 받는 존재여야 하는지를 결정하는 것입니다. 정직한 선택지는 세 가지이며, 옳은 답은 여러분이 감당할 수 있는 예산보다 무엇을 호스팅하는지에 훨씬 더 좌우됩니다.

방식얻는 것치르는 대가
오리진을 직접 노출하되 강화함단순함, 제3자 없음, 여러분이 통제하지 못하는 TLS 종료가 없음주소가 공개되고 영구적임. 7계층은 전적으로 여러분의 몫
상용 CDN 또는 필터링 서비스막대한 흡수 용량, 클릭 한 번으로 뜨는 챌린지 페이지, 글로벌 캐싱여러분의 콘텐츠에 대해 나름의 의견을 가진 신고 처리 부서, 그리고 여러분의 트래픽을 볼 수 있는 회사가 생김. 오프쇼어나 DMCA에 민감한 프로젝트에는 그 외에는 신중하게 짜인 구성에서 가장 약한 고리가 될 수 있음
자체 프론트 노드 — nginx를 실행하며 방화벽으로 보호된 오리진으로 프록시하는 소형 VPS완전한 통제권, 요청 경로에 제3자 없음, 태워 버리고 교체할 수 있는 주소, 그리고 계속 숨겨진 채로 남는 실제 주소자체적인 용량 한계, 그리고 운영해야 할 기기가 하나 더 늘어남. 서로 다른 네트워크에 프론트 두세 개를 두면 무너뜨리기가 훨씬 어려워짐

자체 호스팅 프론트 노드는 보통 받는 것보다 더 많은 관심을 받을 자격이 있습니다. 특히 대형 CDN이 공감하지 못할 법한 이유로 오프쇼어 호스팅을 선택한 사람이라면 더욱 그렇습니다. 이 패턴은 화려하지 않습니다: 저렴한 프록시 노드를 앞에 두고, 오리진은 그 노드들로부터의 연결만 받아들이도록 방화벽을 설정하며, DNS는 프론트를 가리키게 합니다. 프론트가 공격받으면 몇 분 안에 새 주소로 교체하면 되고 오리진은 전혀 눈치채지 못합니다. 이 아키텍처의 전체 버전 — 그럼에도 오리진 주소가 새어 나가는 여섯 가지 경로를 포함해서 — 은 저희의 오리진 서버 IP 숨기기 가이드에서 다룹니다.

숨겨진 오리진은 어떤 필터보다도 가치 있습니다

이는 단도직입적으로 말할 가치가 있습니다. 흔히 여기는 우선순위를 뒤집기 때문입니다: 여러분이 쓸 수 있는 가장 저렴한 DDoS 완화책은 공격자가 갖고 있지 않은 주소입니다. 필터링은 그것이 이미 실패했을 때 하는 일입니다.

이는 들리는 것보다 훨씬 중요합니다. 오리진 주소는 끊임없이, 그리고 조용히 새어 나가기 때문입니다. 프록시를 앞에 두기 전의 오래된 DNS 레코드는 그 변경 이후로도 몇 년씩 살아남습니다. 애플리케이션에서 직접 보낸 메일은 헤더에 그 주소를 싣고 다닙니다. 원본 주소로 발급된 TLS 인증서는 인증서 투명성 로그에 영구적으로 게시됩니다. 오류 페이지, 리다이렉트, 또는 한 번도 프록시를 거치지 않은 눈에 띄지 않는 서브도메인, 이 모두가 정체를 드러냅니다. 예전에 노출되어 있던 서버 앞에 CDN을 두었다면, 바꾸기 전까지는 옛 주소가 알려져 있다고 가정하십시오.

이로부터 따라 나오는 결론은 방화벽 규칙이며, 이 가이드 전체에서 가장 값진 한 줄입니다: 무언가가 앞에 자리하고 나면, 오리진은 그 프론트의 주소를 제외한 모든 곳으로부터의 80번과 443번 포트 연결을 거부해야 합니다. 이것이 없으면 프록시는 그저 권고 사항일 뿐입니다 — 실제 주소를 알아낸 사람은 그저 그것을 돌아가서 여러분을 직접 공격할 뿐이며, 프론트에서 설정한 모든 것이 장식이 되어 버립니다.

공격이 지루한 사건에 그치도록 하드웨어와 위치 고르기

이 중 일부는 공격이 벌어지기 훨씬 전, 플랜을 고르는 그 순간에 이미 결정됩니다. 사양표가 암시하는 것보다 세 가지 속성이 훨씬 더 중요합니다:

  • 무제한 대역폭. 트래픽 종량제 플랜에서는 공격이 장애로 그치지 않고 청구서로도 이어집니다. 여러분이 요청한 적도, 거절할 수도 없었던 트래픽도 여전히 할당량에 산입됩니다. 무제한 전송량은 재정적 위험을 순수하게 기술적인 문제로 바꿔 주며, 이는 훨씬 다루기 나은 부류의 문제입니다.
  • 포트가 여러분만의 것인가. 공유형 가상화 호스트에서는 공격받는 이웃이 여러분에게도 피해를 줄 수 있고, 여러분 자신의 방어 상한선도 함께 나눠 쓰는 것입니다. 자체 포트를 가진 전용 하드웨어는 이 두 효과를 모두 없애 줍니다. 적대적인 관심을 받을 것으로 예상되는 프로젝트라면, 이것이 코어 수나 RAM보다도 VPS에서 한 단계 올라가야 할 가장 분명한 이유입니다.
  • 네트워크가 자리한 위치. 실질적인 트랜짓 용량을 갖춘 연결이 좋은 유럽 네트워크는 피어링이 부실한 네트워크라면 견디지 못할 플러드도 흡수하며, 법적인 이유로 선택한 관할권 역시 나름의 네트워크 특성을 갖고 있습니다. 이용 가능한 위치 중에서 고를 때 이 둘 다 확인해 볼 가치가 있습니다.

단순함을 은근히 편드는 규모의 논리도 있습니다. 캐시 뒤에 있는 평범한 서버 위의 정적 사이트는 무너뜨리기가 대단히 어렵지만, 캐시되지 않은 검색 엔드포인트를 가진 무거운 CMS 위의 똑같은 콘텐츠는 스크립트 하나를 든 의지 있는 한 사람만으로도 무너질 수 있습니다. 동적인 부분을 줄이는 것 자체가 하나의 완화책이며, 게다가 공짜입니다. 여러분의 프로젝트가 정말로 지속적인 부하 아래에서 운영된다면, 저희의 고트래픽 호스팅 노트가 같은 문제의 용량 산정 쪽을 다룹니다.

하지 말아야 할 다섯 가지

여기서의 실패 양상은 목록으로 만들 수 있을 만큼 일관되며, 하나하나가 누군가의 주말을 대가로 치렀습니다:

  • 스스로 널 라우팅하지 마십시오. 자신의 주소를 블랙홀 처리하는 것은 가장 문자 그대로의 방식으로 공격을 끝냅니다 — 사용자를 포함해 아무도 여러분에게 도달할 수 없게 됩니다. 이는 여러분이 자발적으로 취할 조치가 아니라, 제공업체가 쓰는 최후의 수단입니다.
  • fail2ban을 DDoS 방어로 취급하지 마십시오. 소수의 주소에서 오는 브루트포스 시도에는 훌륭한 도구입니다. 분산된 플러드에 대해서는 몇 초 안에 벌어지는 일에 몇 분이 걸려서야 반응하며, 수천 개의 주소를 차단하는 규칙은 방화벽 처리 부담만으로 공격 자체보다 더 큰 비용을 치르게 할 수 있습니다.
  • 몸값을 지불하지 마십시오. 치명적인 공격을 위협하는 갈취 이메일의 압도적 다수는 아무런 능력도 없이 수천 통의 똑같은 메시지를 보내는 사람들이 보낸 것입니다. 실제로 실행에 옮길 수 있는 극소수는 다시 찾아올 것입니다. 여러분이 돈을 낸다는 것을 이미 증명했기 때문입니다.
  • 보복하지 마십시오. 사실상 어디에서나 불법이라는 점을 차치하더라도, 공격에 쓰인 발신지는 장악당한 제3자입니다. 여러분은 피해자를 공격하는 셈이 되며, 그것도 명백히 여러분 것인 주소에서 그렇게 하는 것입니다.
  • 패닉 상태에서 마이그레이션하지 마십시오. 공격 도중에 호스트를 옮기면 몇 분 안에 새 주소가 공개되고, 게다가 제대로 작동하는 설정도 없는 상태가 됩니다. 먼저 안정시키고, 이전은 나중에 신중하게 하십시오 — 그리고 정말 옮겨야 한다면, 저희의 다운타임 없는 마이그레이션 가이드가 바로 그 이전 작업이 제2의 사건이 되지 않도록 존재합니다.

요약

논거를 걷어내면, 실제로 작동하는 모델은 여덟 줄에 담깁니다:

  1. 먼저 분류하십시오. 인터페이스가 포화되어 있으면 볼류메트릭이며 호스트의 몫입니다. 인터페이스는 조용한데 워커가 고갈되어 있으면 7계층이며 여러분의 몫입니다.
  2. 볼류메트릭이라면 주소, 시각, 카운터를 담아 티켓을 접수하십시오 — 그런 다음 서버를 건드리지 마십시오.
  3. 익명 방문자에게는 적극적으로 캐싱하고, 부하가 심할 때는 스테일 콘텐츠를 제공하며, 중복된 캐시 미스는 병합하십시오. 이것이 여러분이 취할 수 있는 가장 레버리지가 큰 변화입니다.
  4. 요청 빈도와 동시성 두 기준으로 속도를 제한하되, 가장 비용이 큰 엔드포인트에서 가장 빡빡하게 걸고, 429를 반환하십시오.
  5. 다른 무엇보다 먼저 real-IP 설정을 고치십시오. 그렇지 않으면 프록시 뒤의 모든 클라이언트별 제한은 무용지물이거나 재앙이 됩니다.
  6. 여러분의 상한선을 알아 두십시오 — 워커, 백로그, 디스크립터, 데이터베이스 연결 — 그리고 평온한 날에 의도적으로 그것들을 올려 두십시오.
  7. 오리진 주소는 비밀로 유지하고 프론트 노드로만 방화벽을 열어 두십시오. 이는 다른 모든 필터를 합친 것보다 가치 있습니다.
  8. 무제한 대역폭을 구매하십시오. 그래야 요청한 적 없는 트래픽이 청구서로 이어지는 일도 없습니다.

이 중 어느 것도 여러분을 면역으로 만들어 주지는 않으며, 면역을 판다는 사람은 다른 무언가를 팔고 있는 것입니다. 이것이 실제로 하는 일은 여러분을 심심한 10대에게 다운될 수 있는 부류에서 벗어나게 해, 실제 자원과 실제 의도가 있어야만 방해할 수 있는 부류로 옮겨 주는 것입니다 — 그리고 압도적 다수의 프로젝트에게 이는 안전과 사실상 구별되지 않습니다. 나머지는 서버를 다른 모든 면에서도 훌륭하게 만드는 것과 같은, 화려할 것 없는 작업입니다: 첫날부터 강화하고, 최악의 날에도 복원할 수 있게 하며, 여러분의 트래픽을 여러분의 사업으로 대우하는 곳에서 운영하는 것입니다.

FAQ

소형 서버의 DDoS — 자주 묻는 질문

01 "DDoS 방어 포함"이면 모든 것으로부터 안전하다는 뜻인가요?

아닙니다. 그리고 그 공백은 막연한 것이 아니라 정확합니다. 포함된 방어는 네트워크 계층 필터링입니다: SYN 플러드, UDP 증폭, 순수 패킷 폭주 같은 볼류메트릭 플러드를 포트에 도달하기 전 업스트림에서 차단합니다. 이는 여러분이 정말로 혼자서는 처리할 수 없는 범주이므로, 포함되는 것이 옳습니다. 다만 애플리케이션은 검사하지 않으므로, 비싼 엔드포인트를 노리는 초당 수천 건 규모의 HTTP 플러드는 아무 제지 없이 그대로 통과해 사이트를 무너뜨리면서도 모든 네트워크 그래프는 정상으로 보이게 만듭니다. 7계층은 여러분이 직접 관리하는 설정입니다: 캐싱, 속도 제한, 연결 상한선입니다.

02 DDoS 공격과 트래픽 급증을 어떻게 구별하나요?

그 트래픽이 무언가를 원하는지 물어보십시오. 인기 있는 링크에서 갑자기 몰려든 방문자라 해도, 실제 방문자는 존재하는 페이지를 요청하고, 그 페이지의 에셋을 로딩하며, 그럴듯한 리퍼러와 함께 도착하고, 자연스러운 패턴으로 여러 네트워크에 걸쳐 퍼져 있습니다. 반면 공격은 대개 경로 하나만 두드리고, 에셋은 무시하며, user-agent가 말이 안 되거나 아예 없고, 인위적으로 보이는 분포를 보입니다. 액세스 로그에서 클라이언트 주소별, 경로별 요청 수를 확인해 보십시오: 엔드포인트 하나가 압도적이고 다른 것은 전혀 로딩되지 않는다면 공격입니다. 사람이 원할 법한 바로 그 페이지들이 서빙되고 있고 리퍼러도 진짜라면, 반가운 원인을 가진 용량 문제입니다.

03 공격을 받는 동안 할 수 있는 가장 효과적인 단 하나의 조치는 무엇인가요?

익명 방문자에 대해 전체 페이지 캐싱을 켜고, 백엔드가 힘겨워할 때 스테일 콘텐츠를 제공하도록 설정하십시오. 속도 제한은 작업을 거부하지만, 캐시는 작업 자체를 없애 버립니다. 데이터베이스 쿼리와 템플릿 렌더링, 애플리케이션 워커 하나를 소모하던 요청이 파일 읽기 하나로 바뀌며, 초당 수백 건의 동적 요청에서 무너졌던 바로 그 하드웨어가 수만 건의 캐시된 요청을 처리하게 됩니다. 이는 또한 목록에 있는 조치 중 실제 트래픽에도 똑같이 도움이 되는 유일한 것이므로, 속도 제한과 달리 여러분 자신의 사용자에게 역효과를 낼 수 없습니다.

04 CDN을 앞에 두고 나서 nginx 속도 제한이 작동하지 않게 된 이유는 무엇인가요?

이제 모든 요청이 방문자의 주소가 아니라 CDN의 주소에서 도착하기 때문에, 클라이언트별 제한이 인터넷 전체를 클라이언트 하나로 취급하게 되기 때문입니다. 임계값에 따라 아예 발동하지 않거나, 여러분의 모든 트래픽을 한꺼번에 차단하게 됩니다. real-IP 소스를 설정하십시오 — nginx에서는 신뢰할 프록시 대역과 프록시가 보내는 헤더입니다 — 그래야 제한이 다시 실제 방문자를 기준으로 걸립니다. 그 신뢰는 프록시 자신의 대역으로만 한정하십시오: 공개 인터넷에서 온 클라이언트 제공 헤더를 그대로 받아들이면, 공격자가 요청마다 새로운 신원을 위조해 여러분이 가진 모든 제한을 그대로 뚫고 지나갈 수 있습니다.

05 fail2ban만으로 DDoS 공격을 막기에 충분한가요?

아닙니다. fail2ban은 일정 간격으로 로그를 읽고 임계값을 넘긴 주소를 차단하는데, 이는 소수의 발신지에서 오는 브루트포스 시도에 적합한 방식입니다. 분산 공격은 각각 몇 건씩만 요청을 보내는 수천 개의 주소에서 몇 초 만에 몰려오므로, 임계값에 아예 도달하지 않을뿐더러 반응 속도도 어차피 너무 느립니다. 더 나쁜 것은, 수만 건으로 불어난 규칙 집합이 공격 자체보다 더 많은 자원을 소모할 수 있다는 점입니다. SSH와 로그인 엔드포인트용으로는 남겨 두고, 플러드는 캐싱과 속도 제한, 업스트림 필터로 다루십시오.

06 CDN을 써야 할까요, 아니면 자체 리버스 프록시를 앞에 두어야 할까요?

이는 예산보다 무엇을 호스팅하는지에 달려 있습니다. 상용 CDN은 여러분이 따라갈 수 없는 흡수 용량과 클릭 한 번이면 뜨는 챌린지 페이지를 제공하지만, 그 대신 CDN의 신고 처리 부서를 함께 떠안게 되고 CDN이 여러분의 트래픽을 볼 수 있게 됩니다 — 오프쇼어나 DMCA에 민감한 프로젝트에는 이것이 그 외에는 신중하게 짜인 구성에서 가장 약한 고리가 되곤 합니다. 자체 프론트 노드는 더 많은 작업을 요구하고 실질적인 용량 한계도 있지만, 요청 경로에 제3자가 없고 공격받는 프론트는 몇 분 안에 새 주소로 교체할 수 있습니다. 어느 쪽이든, 오리진은 프론트로부터 오는 웹 트래픽만 받아들이도록 방화벽으로 잠가야 합니다. 그렇지 않으면 전체 구성이 장식에 불과합니다.

07 공격이 가동 시간뿐 아니라 금전적 비용도 발생시키나요?

트래픽 종량제 플랜이라면 그렇습니다 — 요청한 적도 거절할 수도 없었던 트래픽도 여전히 전송 할당량에 산입되며, 지속적인 플러드는 1년치 호스팅 비용보다 큰 초과 요금 청구서를 만들어 낼 수 있습니다. 이것이 무제한 대역폭이 사양표에서 보이는 것보다 훨씬 중요한 실질적인 이유입니다: 재정적 위험을 순수하게 기술적인 문제로 바꿔 주기 때문입니다. 또한 공격이 공유 인프라를 위협하면 제공업체가 일시적으로 해당 주소를 널 라우팅할 수 있다는 것도 미리 알아 둘 가치가 있습니다. 이는 어디에서나 통용되는 표준적인 관행이지, 여러분이 이용하는 특정 호스트만의 결함이 아닙니다.

08 오프쇼어 또는 노-KYC 호스트로 옮기면 공격을 받을 가능성이 더 커지나요?

호스팅 선택 자체는 중립적입니다. 관심을 끄는 것은 여러분이 무엇을 운영하는가입니다. 게임 서버, 포럼, 스트리밍, 마켓플레이스, 그리고 경쟁자나 원한을 가진 상대가 있는 무엇이든 관할권과 무관하게 공격을 끌어들입니다. 오프쇼어에서 실제로 달라지는 것은 여러분이 기댈 수 있는 대응 수단입니다: 성가시다는 이유만으로 서비스가 끊길 가능성은 낮아지지만, 이는 양날의 검이기도 합니다 — 방어가 계약이 아니라 기술에 달려 있다는 뜻이기 때문입니다. 실질적인 트랜짓 용량을 갖춘 위치를 고르고, 무제한 대역폭을 선택하며, 오리진 주소는 숨겨 두고, 7계층은 첫 사건이 아니라 첫날부터 여러분 자신의 책임으로 다루십시오.

플러드를 걸러내는 곳에 서버를 두십시오

일곱 개 관할권의 오프쇼어 KVM 서버에는 L3/L4 DDoS 필터링, 무제한 대역폭, 완전한 root 권한, NVMe 스토리지가 기본으로 포함됩니다. KYC 없이 암호화폐로 결제하면 트랜잭션이 확인된 지 몇 분 만에 서버가 배포됩니다.

VPS 요금제 보기 전용 서버 오프쇼어 호스팅