클라우드

AWS WAF, 막기 전에 세어 보기

새 방어 규칙이 정상 요청까지 막을 수 있어요. WAF의 Count 동작으로 무엇을 알 수 있고, 오탐은 어디서 찾아야 하는지 살펴봐요.

이 글의 목차세어 보는 모드가 따로 있다3
  1. 세어 보는 모드가 따로 있다
  2. 오탐은 조용히 지나간다
  3. 저는 무엇을 세어 봤나

공항 검색대에 새 규칙을 넣는다고 해 볼게요. 이 물건이 보이면 통과시키지 말라는 규칙이에요. 규칙 자체는 옳을 수 있는데, 그 물건이 승객의 절반이 들고 다니는 흔한 것이라면 검색대는 그날 마비돼요. 규칙이 틀린 것이 아니라 이 줄에 어떤 사람들이 서 있는지 모르고 켠 것이 문제예요.

AWS WAF는 애플리케이션에 도착하기 전의 요청을 규칙으로 걸러 내는 층이에요. 앞 시리즈에서 다룬 보안 그룹이 어디서 왔는지를 보고 판단한다면, 이쪽은 요청의 내용을 보고 판단해요. 그리고 여기서 갈리는 것은 규칙을 무엇으로 채우느냐가 아니라 언제 막기 시작하느냐예요.

세어 보는 모드가 따로 있다

AWS는 운영 트래픽에 새 규칙을 시험할 때 Count, 곧 세기 동작을 사용할 수 있다고 설명해요. 규칙과 일치한 요청을 세되 그 규칙이 차단하지는 않는 거예요. 다만 Count는 검사를 끝내는 동작이 아니어서 뒤의 다른 규칙이 같은 요청을 막을 수 있어요. ‘Count에 걸렸다’와 ‘최종적으로 통과했다’를 같은 뜻으로 읽으면 안 돼요.

같은 문서 묶음에는 세기에서 실제 차단으로 넘기는 단계가 따로 정리돼 있어요. 시험용 규칙을 걷어 내고 동작을 운영 설정으로 바꾸는 절차예요. 서비스가 이 두 단계를 문서에서 나눠 두었다는 사실 자체가, 바로 막는 것이 정상 경로가 아니라는 신호예요.

앞 시리즈의 보안 헤더 편에서 같은 구조를 봤어요. 브라우저에 정책을 걸 때도 보고만 하는 모드로 먼저 켜서 무엇이 걸리는지 며칠 모은 뒤에 실제 차단으로 넘겨요. 도구는 다르지만 이유는 같아요. 내 서비스가 무엇에 의존하고 있는지 저도 전부 알지는 못해요.

집계된 요청이 꼭 통과한 것은 아니에요

같은 예시 요청에 첫 규칙과 뒤 규칙을 다르게 적용해 보세요.

  1. 첫 규칙Count · 1회 집계
  2. 다음 규칙일치 없음
  3. 앱 도착허용

Count는 요청을 세고 다음 규칙으로 보내요. 뒤의 Block에 걸리면 앱에는 도착하지 않아요.

기본 동작은 Allow이며 일치 여부를 미리 정한 예시예요. 실제 관리형 규칙이나 탐지 정확도를 재현하지 않아요.

오탐은 조용히 지나간다

기록 설정에 따른 차단 요청 가시성 정상 요청이 WAF에서 막히고 WAF 기록도 꺼져 있으면 서버와 WAF 어느 기록에도 흔적이 남지 않는다. 개념 도해 기록 설정에 따른 차단 요청 가시성 차단 요청의 기록 경로 ① 정상 요청 ② WAF 판정 정상 입력과 겹침 ③ 차단 서버 미도달 서비스 ④ WAF 기록 설정 기록 켬 · 차단 기록 기록 끔 · 미기록 기록 위치별 남은 흔적 WAF 기록 설정 WAF 기록 서버 기록 서버 오류 지표 기록 켬 차단 기록 기록 없음 변화 없음 기록 끔 기록 없음 기록 없음 신호 없음 관측 위치 정상 요청이 WAF에서 막히고 WAF 기록도 꺼져 있으면 서버와 WAF 어느 기록에도 흔적이 남지 않는다. SOSHIN · DEV NOTES
막힌 사람은 대개 알리지 않아요. 그래서 이 실패는 신고가 아니라 측정으로만 발견돼요.

정상 요청을 공격으로 잘못 판단하는 것을 오탐이라고 해요. 예를 들어 개발자가 게시판에 쓴 데이터베이스 질의 문장이 공격 패턴과 닮을 수 있어요. 이때 요청을 막으면 사용자는 글을 올리지 못해요. WAF 쪽에는 기록이 남을 수 있지만, 앱에는 요청이 도착하지 않아 평소 보던 오류 로그만으로는 놓치기 쉬워요.

증상도 애매해요. 로그인이 안 되는 사람이 백 명 중 세 명이라면 서비스 지표에서는 잘 보이지 않아요. 오류율은 정상이고, 애플리케이션 서버에는 요청이 아예 도착하지 않았으니 그쪽 로그에는 흔적이 없어요. 흔적은 이 층 자신의 로그에만 남는데, 그 로그도 검사한 요청을 어디로 보낼지 따로 설정해야 쌓이기 시작해요. 앞 글에서 다룬 대로 세지 않은 것은 없는 것처럼 보여요.

특히 조심할 대상은 관리형 규칙 묶음이에요. 널리 쓰이는 공격 패턴을 모아 둔 것이라 켜 두면 손이 덜 가지만, 그 안의 규칙 하나가 우리 서비스의 정상 입력과 겹칠 수 있어요. 본문에 특수문자가 많은 글, 파일 이름이 긴 업로드, 길이가 긴 요청 같은 것들이 흔한 충돌 지점이에요. 그래서 묶음 단위로 켜더라도 안쪽 규칙 하나하나의 동작을 개별로 세기로 덮어쓸 수 있게 되어 있고, AWS도 동작을 덮어쓰는 일은 대개 묶음 전체가 아니라 규칙 단위에서 이뤄진다고 안내해요. 묶음을 통째로 끄지 않고도 겹치는 규칙 한 줄만 풀 수 있다는 뜻이에요.

언제 막나잡는 것함께 잃는 것
바로 차단으로 켠다그날부터 공격을 막는다정상 사용자가 조용히 떠난다
세어 보고 나서 막는다겹치는 규칙을 미리 찾는다그 기간 동안은 막지 못한다
세기만 하고 두면아무도 막히지 않는다방어라고 부를 수 없다

세 번째 줄이 실제로 흔해요. 세기 모드로 켜 두고 결과를 검토할 사람이 정해지지 않으면 그대로 몇 달이 가요. 시험 단계에 끝나는 날짜를 함께 정해 두지 않으면 이 상태가 기본값이 돼요.

저는 무엇을 세어 봤나

이 층을 앞에 두면서 가장 신경 쓴 것은 규칙 목록이 아니라 우리 서비스의 정상 요청이 어떻게 생겼는지였어요. 그것을 모르면 어떤 규칙이 겹칠지 예측할 수 없어요.

그래서 순서를 뒤집었어요. 규칙을 고르고 시험하는 대신, 먼저 며칠간 실제 요청이 어떤 모양인지 보고 그다음에 규칙을 골랐어요. 앞 시리즈에서 관측을 이야기하며 무엇을 남길지가 나중에 던질 질문을 정한다고 적었는데, 여기서는 그 기록이 곧 규칙을 고르는 근거가 됐어요.

제게 도움이 된 것은 막힌 요청 수를 줄이는 일보다, 그중에 정상적인 사용이 섞였는지 보는 습관이었어요. 공격을 놓치는 것과 사용자를 잘못 막는 것은 모두 실패예요. 둘 다 우리 서비스의 실제 요청을 알아야 판단할 수 있었어요.

소신을 상징하는 까마귀 목판화 일러스트
작성자소신 · Soshin

웹과 서버를 만들고, 개발하며 배운 것들을 글로 남깁니다.

좌우로 움직여 보세요