네트워크 보안 위협과 방어
MITM과 계층별 DDoS 위협을 이해하고 TLS·방화벽·ACL·WAF·관측을 조합한 다층 방어 전략을 세웁니다.
암호화와 인증서가 통신의 기밀성과 무결성을 보호한다면, 이 절에서는 네트워크와 애플리케이션을 노리는 대표 공격과 방어 전략을 살펴보겠습니다.
보안 방어는 보통 한 장비나 한 헤더로 끝나지 않고, 예방, 탐지, 완화, 복구를 계층별로 조합해야 합니다.
중간자 공격(MITM)
MITM(Man-In-The-Middle)은 통신하는 두 당사자 사이에 공격자가 끼어들어 트래픽을 도청하거나 변조하려는 공격입니다.
같은 Wi-Fi, 악성 프록시, DNS/ARP 조작, 위조 인증서 설치 같은 경로로 시도될 수 있습니다.
HTTPS(TLS)는 MITM의 도청·변조 성공 가능성을 크게 낮추지만, 핵심은 단순 암호화가 아니라 서버 인증, 키 교환 무결성, 전송 데이터 보호입니다.
클라이언트가 인증서 체인과 호스트 이름을 검증하지 않거나, 사용자가 인증서 경고를 무시하거나, 기기에 악성 루트 인증서가 설치되면 보호가 약해질 수 있습니다.
HSTS는 이미 학습한 정책이나 preload가 적용되는 호스트에서 HTTPS를 강제해 downgrade/SSL stripping 위험을 줄입니다. 정책을 아직 모르는 첫 HTTP 접속은 별도로 고려해야 합니다.
DDoS 공격과 계층별 방어
DDoS(Distributed Denial of Service)는 여러 출처에서 대량의 트래픽이나 비싼 요청을 보내 서버, 네트워크, 애플리케이션의 가용성을 떨어뜨리는 공격입니다.
공격 대상에 따라 L3/L4 대역폭·상태 고갈형과 L7 애플리케이션 고비용 요청형으로 나눠 볼 수 있고, 방어는 ISP/클라우드 스크러빙, Anycast/CDN, L3/L4 필터링, SYN 보호, 큐잉, L7 rate limit/WAF를 조합합니다.
- CDN/Anti-DDoS: L3-L7; 엣지에서 흡수·필터링·캐시; 주의점 — 원본 IP 노출과 우회 경로 차단 필요.
- Anycast: L3; 같은 IP를 여러 지역에서 광고해 분산; 주의점 — 라우팅 정책과 용량 계획이 중요.
- Rate Limiting: L7; 사용자·IP·토큰별 요청량 제한; 주의점 — 프록시·NAT·분산 공격에 취약할 수 있음.
- SYN Cookies: L4; 연결 상태를 늦게 만들며 SYN flood 완화; 주의점 — 모든 TCP 공격을 해결하지는 않음.
- Ingress Filtering: L3; 스푸핑된 출발지 주소를 네트워크 경계에서 차단; 주의점 — 운영자 간 협력이 필요.
- WAF/Bot 관리: L7; HTTP 패턴, 평판, 챌린지로 필터링; 주의점 — 오탐·우회·정상 사용자 영향 관리 필요.
- Blackhole Routing: L3; 특정 목적지 트래픽을 폐기; 주의점 — 서비스도 함께 중단될 수 있는 최후 수단.
DNS amplification은 반사 응답을 이용하는 DDoS의 예입니다.
DNS 반사에서 요청과 응답의 목적지
피해자 주소를 질의의 출발지로 위조한 모형입니다. 가정한 메시지 크기와 질의율을 비교합니다. 각 단계의 값과 전환 이유를 비교합니다.
DNS 반사의 주소 관계
위조한 출발지 때문에, 응답은 피해자에게 갑니다
질의의 목적지는 DNS 서버, 응답의 목적지는 피해자입니다. 응답이 질의보다 클 때 증폭되며, 출발지 위조 차단과 외부 재귀 질의 제한은 서로 다른 지점의 방어입니다.
응답이 질의보다 클 때 증폭이 생기며, 크기 비율은 질의·응답에 따라 달라집니다. 출발지 위조 차단과 불필요한 외부 재귀 질의 제한은 서로 다른 지점의 방어입니다.
이 예의 조건
- 본문과 전체 도표의 예를 따라 위조 질의부터 증폭 범위까지 진행합니다.
관계도의 보충 설명
| 구분 | 전체 도표의 내용 |
|---|---|
| 제목 | DNS 반사에서 요청과 응답의 목적지 |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 위조 질의 피해자 주소를 질의의 출발지로 위조한 모형입니다. |
|
|
| 반사 응답 DNS가 질의에 적힌 출발지로 응답합니다. |
|
|
| 증폭 범위 가정한 메시지 크기와 질의율을 비교합니다. |
|
|
DNS 반사에서 요청과 응답의 목적지
피해자 주소를 질의의 출발지로 위조한 모형입니다. 가정한 메시지 크기와 질의율을 비교합니다. 각 단계의 값과 전환 이유를 비교합니다.
DNS 반사의 주소 관계
위조한 출발지 때문에, 응답은 피해자에게 갑니다
질의의 목적지는 DNS 서버, 응답의 목적지는 피해자입니다. 응답이 질의보다 클 때 증폭되며, 출발지 위조 차단과 외부 재귀 질의 제한은 서로 다른 지점의 방어입니다.
응답이 질의보다 클 때 증폭이 생기며, 크기 비율은 질의·응답에 따라 달라집니다. 출발지 위조 차단과 불필요한 외부 재귀 질의 제한은 서로 다른 지점의 방어입니다.
이 예의 조건
- 본문과 전체 도표의 예를 따라 위조 질의부터 증폭 범위까지 진행합니다.
관계도의 보충 설명
| 구분 | 전체 도표의 내용 |
|---|---|
| 제목 | DNS 반사에서 요청과 응답의 목적지 |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 위조 질의 피해자 주소를 질의의 출발지로 위조한 모형입니다. |
|
|
| 반사 응답 DNS가 질의에 적힌 출발지로 응답합니다. |
|
|
| 증폭 범위 가정한 메시지 크기와 질의율을 비교합니다. |
|
|
예시: 반사와 증폭을 계산하기 UDP 질의의 출발지가 피해자 주소로 위조되고, DNS 메시지 크기가 질의 60바이트·응답 1200바이트인 계산 모델을 생각해 봅시다. 응답은 질의를 만든 공격자의 주소가 아니라 위조한 피해자 주소로 갑니다. 크기 비율은 1200÷60=20배입니다. 초당 1000개의 같은 크기 질의에 답하면 피해자로 향하는 DNS 메시지는 초당 1,200,000바이트이고, 질의 쪽은 60,000바이트입니다. IP·UDP 헤더, 손실, 다른 질의 크기는 제외한 예시이며 실제 공격을 실행한 측정이 아닙니다.
출발지 위조를 막는 네트워크 경계의 필터와 의도한 클라이언트에만 재귀 응답을 제공하는 DNS 설정은 서로 다른 지점에서 작동합니다. 권한 DNS는 공개 응답이 필요한 역할이므로 모든 외부 DNS 질의를 일괄 차단하는 해법으로 읽지 않습니다. RFC5358의 재귀 DNS 반사 방어 범위를 함께 확인하세요.
방화벽과 ACL
방화벽(Firewall)은 네트워크 트래픽을 규칙에 따라 허용하거나 차단합니다.
ACL은 보통 “어떤 출발지/목적지/포트/프로토콜을 허용할지”를 명시하는 규칙 목록이고, stateful firewall은 연결 상태까지 추적합니다. 규칙의 평가 순서와 기본 허용·차단 정책은 제품과 설정에 따라 확인해야 합니다.
방화벽은 불필요한 노출면을 줄이는 기본 방어선이지만, 허용된 포트 안에서 발생하는 SQL Injection, XSS, 인증 우회 같은 애플리케이션 취약점까지 자동으로 해결하지는 못합니다.
암호화된 트래픽 내부를 보려면 TLS 복호화 프록시, 내부 인증서 배포, 개인정보·성능 검토가 필요합니다.
그래서 네트워크 방화벽, 보안 그룹, 세그먼테이션, WAF, 애플리케이션 보안 점검을 함께 봐야 합니다.
WAF와 보안 관측
WAF(Web Application Firewall)는 HTTP 계층에서 동작하며 요청의 URL, 헤더, 쿠키, 본문 패턴을 분석해 웹 공격을 탐지하거나 차단합니다.
일반 방화벽이 IP와 포트 중심이라면, WAF는 HTTP 대화의 내용을 다룹니다.
다만 정상 요청처럼 보이는 비즈니스 로직 남용, 인증·인가 오류, 우회 인코딩, API 스키마 미반영, 오탐과 미탐은 애플리케이션 설계와 운영 튜닝으로 함께 다뤄야 합니다.
- IDS: L3-L7; 침입 징후 탐지와 알림; 한계 — 직접 차단하지 않는 구성이 많음.
- IPS: L3-L7; 탐지 후 인라인 차단; 한계 — 오탐이면 정상 트래픽 차단 가능.
- WAF: L7; 웹 공격 패턴 탐지·차단; 한계 — 비즈니스 로직 취약점은 별도 설계 필요.
- SIEM: 전 계층; 로그 상관분석과 경보; 한계 — 로그 품질과 룰 튜닝에 성능이 좌우됨.
- EDR: 엔드포인트; 단말 행위 기반 탐지·대응; 한계 — 네트워크 앞단의 대량 트래픽 흡수와는 다름.
import time
from collections import defaultdict
class RateLimiter:
"""단일 프로세스 예시용 토큰 버킷 Rate Limiter"""
def __init__(self, max_tokens, refill_rate):
self.max_tokens = max_tokens
self.refill_rate = refill_rate # 초당 충전 토큰 수
self.buckets = defaultdict(lambda: {
"tokens": max_tokens,
"last_refill": time.time(),
})
def allow_request(self, client_key):
bucket = self.buckets[client_key]
now = time.time()
elapsed = now - bucket["last_refill"]
bucket["tokens"] = min(
self.max_tokens,
bucket["tokens"] + elapsed * self.refill_rate,
)
bucket["last_refill"] = now
if bucket["tokens"] >= 1:
bucket["tokens"] -= 1
return True
return False
# 단일 인스턴스 예시: 초당 10개 요청, 버스트 최대 20개
limiter = RateLimiter(max_tokens=20, refill_rate=10)
for i in range(25):
key = "user:42"
if limiter.allow_request(key):
print(f"요청 {i + 1}: 허용")
else:
print(f"요청 {i + 1}: 제한")위 코드는 단일 스레드의 알고리즘 이해용입니다. 25번 반복 중 허용 횟수는 실제 경과 시간에 따라 달라지며 실행 관측값을 제시하지 않습니다. time.time()은 시스템 시계 조정의 영향을 받으므로 경과 시간 측정에는 단조 시계가 적합합니다. 현재 예제에는 동시 호출 잠금, 오래된 키 제거, 입력 범위 검증이 없습니다.
토큰의 변화를 따라 계산하기 계산을 분리하기 위해 키의 버킷 생성과 25개의 요청이 모두 같은 시각 t=0에 일어났다고 합시다. 초기 토큰 20개에서 요청마다 1개씩 소비하므로 20개가 허용되고 5개가 거부됩니다. 거부도 토큰을 음수로 만들지는 않습니다. 추가 요청 없이 t=0.15초에 다음 요청이 오면 0+0.15×10=1.5개로 충전되고, 그 요청을 허용한 뒤에는 0.5개가 남습니다. 같은 시각의 다음 요청은 1개 미만이므로 거부됩니다.
이 예의 초당 충전량 10은 임의의 모든 1초 구간에 최대 10개만 허용한다는 고정 창 상한이 아닙니다. 처음에는 최대 20개의 버스트가 가능하고, 이후 경과 시간에 따라 토큰을 채웁니다. 실제 원 코드의 25회 반복은 서로 시간이 흐르므로 위 t=0 모델과 고정 출력이 같다고 단정하지 않습니다.
배치 조건을 독립적으로 바꾸기 같은 사용자 키의 빈 이력을 가진 A와 B 서버가 각각 별도의 max_tokens=20 버킷을 사용합니다. 같은 시각에 A로 20개, B로 20개 요청이 오면 전체 몇 개가 허용될까요? 공통으로 적용하려던 버스트 상한 20개가 보장되는지도 설명하세요.
프로세스별 상태와 전체 정책의 풀이
각 버킷은 20개를 허용하므로 합계 40개입니다. 단일 인스턴스의 계산이 맞아도 서버 사이에 상태를 공유하지 않으면 공통 상한이 되지 않습니다. 공유 저장소를 사용한다면 검사·충전·차감의 동시성까지 하나의 정책으로 설계해야 합니다. 연결을 허용한 방화벽 규칙이나 WAF가 있다는 사실만으로 이 사용자별 애플리케이션 정책이 자동으로 만들어지는 것도 아닙니다.
운영 환경에서는 여러 서버가 동시에 요청을 받으므로 Redis 같은 공유 저장소, 엣지 rate limit, 사용자 ID·IP·토큰 조합 키, 프록시 헤더 신뢰 정책, 모니터링을 함께 설계해야 합니다.
다음 장에서는 네트워크 이론을 코드로 직접 구현해 보는 소켓 프로그래밍을 다루겠습니다.