NGINX 및 NGINX Plus로 DDoS 공격 완화하기

Distributed Denial-of-Service(DDoS) 공격은 리소스 부족으로 인해 서비스를 제공하는 서버가 더 이상 정상적으로 작동할 수 없을 정도로 여러 컴퓨터에서 대량의 트래픽을 발생시켜 서비스를 사용할 수 없게 만들려고 시도하는 공격입니다.

일반적으로 공격자는 너무 많은 연결과 요청으로 시스템을 과부화 시켜 더 이상 새로운 트래픽을 수용할 수 없거나 속도가 너무 느려져 사실상 사용할 수 없게 만들려고 시도합니다.

목차

1. 애플리케이션 계층 DDoS 공격 특성
2. NGINX 및 NGINX Plus를 사용하여 DDoS 공격에 대응하기
2-1. NGINX 이벤트 중심 아키텍처의 고유한 보호 기능
2-2. 요청 속도 제한
2-3. 연결 수 제한
2-4. Slow Connection 종료
2-5. IP 주소 거부 목록 지정
2-6. IP 주소 허용 목록 지정
2-7. 캐싱을 사용하여 트래픽 급증을 원활하게 처리하기
2-8. 요청 차단하기
2-9. Backend 서버에 대한 연결 제한하기
3. DDoS 공격 식별
4. NGINX DDoS 방어 요약

1. 애플리케이션 계층 DDoS 공격 특성

애플리케이션 계층( 7 계층 / HTTP) DDoS 공격은 특정 시스템의 취약점을 가장 잘 공격하도록 구성된 소프트웨어 프로그램(Bot)에 의해 수행됩니다. 예를 들어, 많은 수의 동시 연결을 잘 처리하지 못하는 시스템의 경우 많은 수의 연결을 열고 주기적으로 소량의 트래픽을 전송하여 활성 상태로 유지하는 것만으로도 시스템의 새로운 연결을 위한 용량을 소진할 수 있습니다. 다른 공격은 많은 수의 요청 또는 매우 큰 요청을 보내는 형태를 취할 수 있습니다. 이러한 공격은 실제 사용자가 아닌 Bot에 의해 수행되기 때문에 공격자는 손쉽게 수많은 연결을 열고 대량의 요청을 매우 빠르게 전송할 수 있습니다.

DDoS 공격을 방어하는 데 사용할 수 있는 DDoS 공격의 특성은 다음과 같습니다(이 목록은 완전하지는 않습니다).

  • 트래픽은 일반적으로 공격을 수행하는 데 사용되는 컴퓨터에 속하는 고정된 IP 주소 집합에서 발생합니다. 따라서 각 IP 주소는 실제 사용자가 예상하는 것보다 훨씬 더 많은 연결과 요청을 수행합니다.

    Note: 이 트래픽 패턴이 항상 DDoS 공격을 의미한다고 가정하지 않는 것이 중요합니다. Forward Proxy 서버의 IP 주소가 서비스를 제공하는 모든 실제 클라이언트의 요청에 대한 클라이언트 주소로 사용되기 때문에 Forward Proxy를 사용하는 경우에도 이러한 패턴이 발생할 수 있습니다. 그러나 Forward Proxy의 연결 및 요청 수는 일반적으로 DDoS 공격보다 훨씬 적습니다.
  • 트래픽은 Bot에 의해 생성되고 서버를 과부화 시키기 위한 것이므로 트래픽의 속도는 일반적인 사용자가 생성할 수 있는 것보다 훨씬 높습니다.
  • User-Agent 헤더가 때때로 표준값이 아닌 값으로 설정되는 경우가 있습니다.
  • Referer 헤더는 공격과 연관 지을 수 있는 값으로 설정되는 경우가 많습니다.

2. NGINX 및 NGINX Plus를 사용하여 DDoS 공격에 대응하기

NGINX와 NGINX Plus에는 위에서 언급한 DDoS 공격의 특성과 함께 DDoS 공격 완화 솔루션의 중요한 일부가 될 수 있는 여러 가지 기능이 있습니다. 이러한 기능은 들어오는 트래픽을 조절하고 Backend 서버로 Proxy되는 트래픽을 제어하여 DDoS 공격에 대응합니다.

2-1. NGINX 이벤트 중심 아키텍처의 고유한 보호 기능

NGINX는 사이트 또는 애플리케이션의 ‘충격 흡수 장치’ 역할을 하도록 설계되었습니다. Non‑Blocking, 이벤트 중심 아키텍처로 리소스 사용량이 눈에 띄게 증가하지 않으면서도 엄청난 양의 요청에 대처할 수 있습니다.

네트워크에서 새로운 요청이 들어와도 NGINX가 진행 중인 요청을 처리하는 데 방해가 되지 않으므로 NGINX는 사이트 또는 애플리케이션을 공격으로부터 보호하는 아래에 설명된 기술을 적용할 수 있는 용량을 확보하고 있습니다.

2-2. 요청 속도 제한

NGINX 및 NGINX Plus가 들어오는 요청을 허용하는 속도를 실제 사용자에게 나타나는 일반적인 값으로 제한할 수 있습니다. 예를 들어 로그인 페이지에 액세스하는 실제 사용자는 2초마다 한 번만 요청할 수 있도록 설정할 수 있습니다. 단일 클라이언트 IP 주소가 2초마다(분당 30건의 요청에 해당) 로그인을 시도하도록 NGINX 및 NGINX Plus를 구성할 수 있습니다.

limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;

server {
    # ...
    location /login.html {
        limit_req zone=one;
    # ...
    }
}

limit_req_zone 지시문은 지정된 키(이 경우 클라이언트 IP 주소)에 대한 요청 상태를 저장하기 위해 one이라는 공유 메모리 Zone을 구성합니다($binary_remote_addr). /login.html의 location 블록에 있는 limit_req 지시문은 공유 메모리 Zone을 참조합니다.

2-3. 연결 수 제한

단일 클라이언트 IP 주소가 연결할 수 있는 연결 수를 실제 사용자에게 적합한 값으로 제한할 수 있습니다. 예를 들어, 각 클라이언트 IP 주소가 웹사이트의 /store 영역에 대해 10개 이하의 연결만 열도록 지정할 수 있습니다.

limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    # ...
    location /store/ {
        limit_conn addr 10;
        # ...
    }
}

limit_conn_zone 지시문은 지정된 키(이 예에서는 앞의 예에서와 같이 클라이언트 IP 주소인 $binary_remote_addr)에 대한 요청을 저장하기 위해 addr이라는 공유 메모리 Zone을 구성합니다. store에 대한 location 블록의 limit_conn 지시문은 공유 메모리 Zone을 참조하고 각 클라이언트 IP 주소에서 최대 10개의 연결을 설정합니다.

2-4. Slow Connection 종료

데이터 쓰는 빈도가 너무 낮은 연결을 연결 해제할 수 있는데, 이는 연결을 가능한 한 오래 열어두려는 시도일 수 있습니다. 따라서 서버가 새 연결을 수락하는 기능이 저하됩니다. Slowloris가 이러한 유형의 공격의 한 예입니다. client_body_timeout 지시문은 클라이언트 본문의 쓰기 사이에 NGINX가 대기하는 시간을 제어하고, client_header_timeout 지시문은 클라이언트 헤더의 쓰기 사이에 NGINX가 대기하는 시간을 제어합니다. 두 지시문의 기본값은 60초입니다. 이 예에서는 클라이언트에서 헤더 또는 본문 쓰기 사이에 5초 이상 기다리지 않도록 NGINX를 구성합니다.

server {
    client_body_timeout 5s;
    client_header_timeout 5s;
    # ...
}

2-5. IP 주소 거부(deny) 목록 지정

공격에 사용되는 클라이언트 IP 주소를 식별할 수 있는 경우 deny 지시문을 사용하여 해당 주소를 deny 목록에 추가하여 NGINX 및 NGINX Plus가 해당 연결 또는 요청을 수락하지 않도록 할 수 있습니다. 예를 들어, 공격이 123.123.123.1 ~ 123.123.123.16 주소 범위에서 발생하는 것으로 확인된 경우입니다.

location / {
    deny 123.123.123.0/28;
    # ...
}

또는 클라이언트 IP 주소 123.123.123.3, 123.123.123.5, 123.123.123.7에서 공격이 발생하는 것으로 확인된 경우입니다.

location / {
    deny 123.123.123.3;
    deny 123.123.123.5;
    deny 123.123.123.7;
    # ...
}

2-6. IP 주소 허용(allow) 목록 지정

하나 이상의 특정 클라이언트 IP 주소 집합 또는 범위에서만 웹사이트 또는 애플리케이션에 대한 액세스를 허용하는 경우 allow 지시문과 deny 지시문을 함께 사용하여 해당 주소만 사이트 또는 애플리케이션에 액세스할 수 있도록 허용할 수 있습니다. 예를 들어 특정 로컬 네트워크의 주소로만 액세스를 제한할 수 있습니다.

location / {
    allow 192.168.1.0/24;
    deny all;
    # ...
}

여기서 모든 것을 거부(deny)하는 지시문은 allow 지시문에서 지정한 범위에 속하지 않는 모든 클라이언트 IP 주소를 차단합니다.

2-7. 캐싱을 사용하여 트래픽 급증을 원활하게 처리하기

캐싱을 활성화하고 특정 캐싱 매개변수를 설정하여 Backend의 요청을 Offload함으로써 공격으로 인해 발생하는 트래픽 급증을 상당 부분 흡수하도록 NGINX 및 NGINX Plus를 구성할 수 있습니다. 몇 가지 유용한 설정은 다음과 같습니다.

  • proxy_cache_use_stale 지시문의 업데이트 매개변수는 오래된 캐시 객체의 업데이트를 가져와야 할 때 업데이트 요청을 한 번만 보내고 Backend 서버에서 업데이트를 받는 데 걸리는 시간 동안 요청하는 클라이언트에게 오래된 객체를 계속 제공하도록 NGINX에 지시합니다. 특정 파일에 대한 반복적인 요청이 공격의 일부인 경우 Backend 서버에 대한 요청 횟수를 크게 줄일 수 있습니다.
  • proxy_cache_key 지시문으로 정의된 키는 일반적으로 임베디드 변수로 구성됩니다(기본 키인 $scheme$proxy_host$request_uri에는 3개의 변수가 있습니다). 값에 $query_string 변수가 포함되어 있으면 임의의 쿼리 문자열을 전송하는 공격으로 인해 과도한 캐싱이 발생할 수 있습니다. 특별한 이유가 없는 한 $query_string 변수를 키에 포함하지 않는 것이 좋습니다.

2-8. 요청 차단하기

여러 종류의 요청을 차단하도록 NGINX 또는 NGINX Plus를 구성할 수 있습니다.

  • 타겟팅된 것으로 보이는 특정 URL에 대한 요청
  • User-Agent 헤더가 정상적인 클라이언트 트래픽에 해당하지 않는 값으로 설정된 요청
  • Referer 헤더가 공격과 연관될 수 있는 값으로 설정된 요청
  • 다른 헤더에 공격과 연관될 수 있는 값이 있는 요청

예를 들어, DDoS 공격이 /foo.php URL을 표적으로 삼고 있다고 판단되면 해당 페이지에 대한 모든 요청을 차단할 수 있습니다.

location /foo.php {
    deny all;
}

또는 DDoS 공격 요청의 User-Agent 헤더 값이 foo 또는 bar인 것을 발견하면 해당 요청을 차단할 수 있습니다.

location / {
    if ($http_user_agent ~* foo|bar) {
        return 403;
    }
    # ...
}

http_name 변수는 요청 헤더를 참조하며, 위의 예에서는 User-Agent 헤더를 참조합니다. 공격을 식별하는 데 사용할 수 있는 값이 있는 다른 헤더에도 비슷한 접근 방식을 사용할 수 있습니다.

2-9. Backend 서버에 대한 연결 제한하기

NGINX 또는 NGINX Plus 인스턴스는 일반적으로 Load Balancing하는 Backend 서버보다 훨씬 많은 수의 동시 연결 처리가 가능합니다. NGINX Plus를 사용하면 각 Backend 서버에 대한 연결 수를 제한할 수 있습니다. 예를 들어 아래는, website Upstream 그룹에 있는 두 Backend 서버 각각에 대한 연결을 200개 이하로 설정하도록 NGINX Plus를 제한하려는 경우입니다.

upstream website {
    server 192.168.100.1:80 max_conns=200;
    server 192.168.100.2:80 max_conns=200;
    queue 10 timeout=30s;
}

각 서버에 적용되는 max_conns 매개 변수는 NGINX Plus가 해당 서버에 열 수 있는 최대 연결 수를 지정합니다. queue 지시문은 Upstream 그룹의 모든 서버가 연결 제한에 도달했을 때 대기 중인 요청의 수를 제한하고, timeout 매개변수는 요청을 대기열에 보관할 시간을 지정합니다.

3. DDoS 공격 식별

지금까지 NGINX와 NGINX Plus를 사용하여 DDoS 공격의 영향을 완화할 수 있는 방법에 대해 집중적으로 살펴보았습니다. 그렇다면 NGINX 또는 NGINX Plus는 어떻게 DDoS 공격을 식별하는 데 도움이 될 수 있을까요? NGINX Plus Status 모듈은 Backend 서버로 Load Balancing되는 트래픽에 대한 자세한 지표를 제공하여 비정상적인 트래픽 패턴을 파악하는 데 사용할 수 있습니다. NGINX Plus는 NGINX Plus 시스템의 현재 상태를 그래픽으로 보여주는 상태 대시보드 웹 페이지와 함께 제공됩니다(demo.nginx.com에서 예시 참조). API를 통해서도 동일한 지표를 사용할 수 있으며, 이 지표를 사용자 정의 또는 타사 모니터링 시스템에 제공하여 과거 추세 분석을 통해 비정상적인 패턴을 발견하고 알림을 활성화할 수 있습니다.

4. NGINX DDoS 방어 요약

NGINX와 NGINX Plus는 DDoS 방어 솔루션의 중요한 부분으로 사용할 수 있으며, NGINX Plus는 DDoS 공격으로부터 보호하고 공격 발생 시점을 식별하는 데 도움이 되는 추가 기능을 제공합니다.

NGINX 및 NGINX Plus를 사용하여 DDoS를 구성해 테스트해 보려면 지금 30일 무료 평가판을 신청하거나 사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.

NGINX STORE 뉴스레터 및 최신 소식 구독하기

* indicates required