웹 요청을 살피는 WAF를 붙였다 — 공격 차단과 정상 서비스 사이

2026년 10월 28일, 운영 중인 웹서비스에 WAF를 추가했다. WAF는 웹 요청을 살펴보고 공격으로 판단한 요청을 막는 웹 방화벽이다. 처음에는 탐지 모드로 운영하며 요청을 살펴본 뒤 차단 모드로 전환했다.

서버를 관리하다 보면 존재하지 않는 설정 파일이나 관리 페이지를 찾는 요청이 눈에 들어온다. 기존에도 이런 접근을 막고 있었지만 요청 내용까지 살펴볼 수 있도록 보안 구성을 보완하기로 했다. 이번 글에는 설치 방법을 길게 적기보다 적용하면서 확인한 것들을 남겨 보려고 한다.

개인 서비스를 운영하면 기능을 만드는 일 외에도 챙길 것이 생긴다. 페이지가 잘 열리는지 확인하는 것만으로는 서버에서 어떤 요청을 받고 있는지 알기 어렵다. 화면에서는 별다른 변화가 없어도 그 뒤에서 처리되는 요청은 따로 살펴봐야 한다. 이번 WAF 작업도 사용자가 보는 화면을 바꾸는 일보다는 서비스에 들어오는 요청을 다루는 쪽에 가까웠다.

쓰던 보안 규칙은 유지하면서

이번에는 Nginx에 ModSecurity와 OWASP CRS를 연결했다. 웹서버가 받는 요청을 검사하고 알려진 공격 유형을 찾아내는 구성이다. 기존 접근 제한과 Fail2ban은 유지하고 WAF를 함께 적용했다.

새 기능을 추가할 때는 원래 동작하던 부분이 유지되는지도 살펴야 한다. 이번에도 기존에 막고 있던 요청과 차단 정보를 그대로 보존하는 쪽으로 진행했다. 새로 붙인 기능만 확인하고 끝내면 그 과정에서 달라진 다른 부분을 놓칠 수 있기 때문이다. 적용 전후를 비교할 때도 WAF의 동작과 기존 보안 구성을 함께 확인했다.

서비스마다 같은 설정을 따로 관리하면 나중에 수정할 때 빠뜨리는 곳이 생길 수 있다. 공통으로 적용할 부분을 정리하면서 각 서비스에 이미 있던 제한도 보존했다. 적용 후에는 실제 요청을 보내 검사 기록이 남는지 확인했다. 설정을 넣었다는 사실과 요청을 검사하고 있다는 사실을 나눠서 본 것이다.

공식 소스를 확인해 빌드하고 검증한 뒤 운영 서버에 적용했다. 별도로 준비한 패키지인 만큼 이후 보안 업데이트도 직접 챙겨야 한다. 설치로 끝나는 작업은 아니라는 점을 운영 기록에 남겼다. 새 버전이 나왔을 때 무엇을 다시 확인해야 하는지 알 수 있도록 준비 과정과 검증 결과도 함께 정리했다.

웹 요청을 Nginx와 WAF가 검사해 정상 요청 전달과 공격 요청 차단으로 나누고 탐지 기록을 집계하는 개념도
WAF 동작 원리를 설명한 AI 생성 개념도. 실제 운영 화면과 설정을 나타내지 않는다.

잘 막는 것만큼 평소처럼 쓸 수 있는지도

보안 기능을 붙일 때는 정상적인 사용이 불편해지지 않는지도 중요하다. 공격 요청을 막더라도 평소에 열리던 페이지나 사용하던 기능에 문제가 생긴다면 원인을 찾아야 한다. 그래서 차단 여부를 확인하는 동안 정상 요청을 함께 비교했다.

화면에 오류가 뜬다는 이유만으로 WAF가 차단했다고 판단하지는 않았다. 기존 접근 제한이나 앱에서 만든 응답일 수도 있어서 기록을 함께 살폈다. 겉으로는 비슷하게 보이는 오류라도 어디에서 발생했는지에 따라 확인할 곳과 수정할 부분이 달라진다. 이 구분 없이 설정부터 바꾸면 원래 문제가 있던 곳은 그대로 둔 채 다른 동작만 바꿀 수 있다.

시험에서는 정상 요청과 공격 형태의 요청을 비교하고 실제 거부 동작도 확인했다. 적용 전후의 웹 응답을 살피고 기존 차단 정보가 유지되는지도 확인했다. 앱으로 전달해야 하는 요청은 중간에서 내용이 달라지지 않았는지 함께 봤다.

이렇게 확인해도 모든 기능과 상황을 한 번에 검증할 수는 없다. 몇 가지 요청이 잘 처리됐다는 결과를 전체 서비스가 모든 상황에서 괜찮다는 뜻으로 받아들이지는 않았다. 시험한 범위를 남겨 두고 이후 실제 사용 중의 오류와 영향을 계속 살피는 일이 필요하다. 정상적으로 쓰던 기능에 문제가 생겼을 때 비교할 기준을 마련하는 과정이기도 했다.

로그를 남길 때도 조심하기

검사 결과를 자세히 남기면 문제를 찾기에는 편하다. 하지만 요청에 담긴 내용이나 로그인에 쓰이는 정보까지 저장하면 로그 자체가 민감한 자료가 된다. 이번에는 그런 정보가 WAF 감사 로그에 남지 않도록 기록 범위를 줄이고 시험용 값을 넣어 실제 기록도 확인했다.

나중에 필요할지 모른다는 이유로 모든 내용을 쌓아 두는 방식은 피하고 싶었다. 원인을 살펴보는 데 필요한 기록과 사용자가 보낸 내용을 구분하고 상태 화면에서도 상세 요청 대신 집계한 결과를 보여 주도록 했다. 그렇다고 모든 종류의 로그에 같은 기준이 적용됐다고 단정할 수는 없다. 기록마다 역할이 다르므로 실제 남는 항목을 확인하는 과정이 필요했다.

기록을 계속 쌓는 과정에서도 손볼 부분이 있었다. 로그 파일을 정리한 뒤에도 이전 파일에 기록이 이어지는 문제가 있어 처리 방식을 조정했다. 이후 새 기록이 남는지 다시 확인하고 남은 제약은 운영 문서에 적어 두었다. 처음 한 번 기록이 생기는 것과 계속 운영하는 동안 기록이 이어지는 것은 별도로 확인할 일이었다.

숫자를 볼 때도 구분이 필요했다

상태 화면에서는 탐지와 실제 차단을 구분했다. 어느 정도의 요청이 검사에 걸렸고 그중 무엇이 거부됐는지 나눠 볼 수 있도록 했다. 차단 조건에 해당하는 것으로 판단한 요청도 실제 거부 기록과 섞이지 않게 정리했다.

숫자가 많아 보이는 것보다 그 숫자가 무엇을 뜻하는지 아는 편이 운영할 때 도움이 된다. 집계 기준이 다른 값을 한데 놓으면 이전보다 공격이 늘었는지, 기록 방식이 바뀌었는지부터 헷갈릴 수 있다. 충분한 정보가 없는 과거 기록은 억지로 분류하지 않았다. 화면에서는 기간을 바꾸고 그래프의 값을 확인하는 흐름도 살펴봤다.

적용한 뒤에도 확인할 것들

WAF를 붙였다고 앱 안의 보안 문제까지 모두 해결되는 것은 아니다. 입력값을 검사하고 접근 권한을 확인하는 일, 발견된 문제를 수정하고 업데이트하는 일은 계속 필요하다. 새로 추가한 보안 기능도 기존 서비스와 함께 관리할 대상으로 남는다.

이번 작업에서는 공격 요청을 다루는 기능을 추가하면서 정상 요청과 기존 보안 규칙, 로그에 남는 정보까지 함께 살펴봤다. 설치 여부만 확인했다면 지나쳤을 부분들이다. 나중에 설정을 바꾸거나 문제가 생겼을 때 참고할 수 있도록 확인한 내용도 남겼다.

공개 글에는 서버 주소와 계정, 세부 설정은 담지 않았다. 그림 역시 실제 운영 화면이 아닌 설명용 개념도다. 운영에 필요한 상세 기록은 따로 관리하고 이곳에는 WAF를 적용하며 어떤 부분을 신경 썼는지 남겨 둔다. 다음에 비슷한 작업을 할 때도 설치 과정뿐 아니라 적용 전후에 무엇을 비교했는지 함께 돌아볼 수 있으면 좋겠다.

참고: OWASP CRS 공식 문서

#개발 #Nginx #서버관리 #보안 #WAF #ModSecurity #OWASP CRS

댓글 0

    댓글 남기기