왜
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 를 키로 확보한 뒤 적용 |
정확. 프론트 조율이 선행 |
참고
왜
nginx 에 요청 빈도 제한(
limit_req)만 있고 연결 계열 방어가 통째로 없다. #928 작업 중 실측한 현황이다.limit_reqpiki_general초당 20)client_max_body_sizelimit_connclient_header_timeoutclient_body_timeoutsend_timeoutlimit_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번째부터 실시간 알림이 끊긴다.limit_conn에서 빼거나 별도 zone 으로 분리참고
piki_general을 조이면 안 되는 이유)