Skip to content

nginx 연결 계열 DoS 방어 추가 (limit_conn·타임아웃) #970

Description

@m-a-king

nginx 에 요청 빈도 제한(limit_req)만 있고 연결 계열 방어가 통째로 없다. #928 작업 중 실측한 현황이다.

설정 상태 막는 것
limit_req 있음 (piki_general 초당 20) 요청 빈도
client_max_body_size 있음 (25M) 거대 바디
limit_conn 없음 동시 연결 수 (연결 고갈)
client_header_timeout 없음 Slowloris (헤더를 천천히 보내며 점유)
client_body_timeout 없음 바디를 천천히 보내는 변종
send_timeout 없음 응답을 천천히 받아가며 점유

limit_req 는 "빨리 많이" 를 막는다. Slowloris 는 반대로 느리게 조금씩 보내 연결만 붙잡으므로 빈도가 낮아 레이트리밋에 안 걸린다. 타임아웃이 미설정이라 nginx 기본값(헤더 60s, keepalive 75s)이 적용되는데, 이 값은 공격자에게 넉넉하다.

무엇을

두 덩어리이고 난이도가 다르다.

1. 타임아웃 3종 (선행 가능)

client_header_timeout · client_body_timeout · send_timeout 을 짧게 명시하고 reset_timedout_connection 을 검토한다. 프록시 뭉침과 무관하므로 limit_conn 과 분리해 먼저 넣을 수 있다.

2. limit_conn (설계 결정 필요)

그냥 넣으면 정상 사용자가 먼저 끊긴다.

프론트가 /api/v1/* 를 리버스 프록시해 웹 사용자 전원이 프록시 egress IP 하나로 묶인다(#928 실측). limit_req 는 실측이 한도의 0.1% 라 여유가 1,200배였지만, limit_conn동시 접속자 수가 곧 카운트라 여유가 훨씬 적다.

특히 SSE 구독(/api/v1/notifications/subscribe)은 오래 열린 연결이고 그 경로도 프록시를 탄다. IP당 10 으로 잡으면 웹 사용자 11번째부터 실시간 알림이 끊긴다.

설계안 방법 트레이드오프
SSE 경로 예외 SSE location 을 limit_conn 에서 빼거나 별도 zone 으로 분리 간단. 다만 그 경로 자체는 무제한이라 SSE 로 연결 고갈이 가능
원 IP 승격 선행 프록시 신원 확인으로 실 IP 를 키로 확보한 뒤 적용 정확. 프론트 조율이 선행

참고

Metadata

Metadata

Assignees

Labels

infra운영 환경 (IaC·클라우드 리소스·secret·배포 workflow)

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions