Issuefy 프로젝트에 통합 모니터링을 도입한 이후 하루에 한 번 이상은 특별한 이슈가 없어도 로그를 보고 있습니다.
Issuefy의 API 서버는 Spring 프레임워크를 기반으로 구축되었으며, GitHub OAuth를 통해서만 로그인할 수 있습니다. 또한, JWT 기반의 인증 체계를 사용하고 있어 유효하지 않은 JWT 토큰을 포함한 요청은 인증 필터에서 거부됩니다.
의심스러운 로그 탐지
그런데 로그를 모니터링하던 중 이상한 점을 발견하게 되었습니다. 인증 필터에서 지속적으로 차단하고 있는 요청들이 있었던 것입니다. 아직 개발이 완료되지 않은 상황이라 팀원들은 모두 로컬 서버에서 작업하고 있었고, 배포 서버로 요청을 보낼 만한 사람이 없었기에 이는 매우 의심스러운 상황이었습니다.
원인 파악
원인을 파악하기 위해 먼저 의심스러운 요청에 대한 정보를 더 많이 수집할 필요가 있었습니다.
기존의 로깅 전략으로는 요청의 출처와 목적을 파악하기 어려웠기 때문입니다.
의심스러운 요청은 필터에 의해 적절히 차단되고 있었기에 즉각적인 위험은 없다고 판단했습니다.
따라서 로깅 전략을 개선하여 원인 파악을 분명히 하고자 했습니다.
모든 요청에 대해 클라이언트 IP, 사용자 정보, 요청 URL을 로그에 기록하도록 변경했습니다.
서버는 ALB뒤에서 동작하고 있었고, ALB는 클라이언트의 실제 IP를 X-Forwarded-For 헤더에 담아 서버에 전달하도록 이미 설정되어 있었습니다. 이를 활용하면 의심스러운 요청의 실제 출처를 파악할 수 있을 것이라고 생각했습니다.
이에 새로운 로깅 전략을 적용하기 위해 코드를 수정하고 hotfix로 배포했습니다.
개선된 로깅 전략을 적용한 지 얼마 지나지 않아 아래와 같은 로그가 포착되었습니다.
Issuefy 서버에는 존재하지 않는 .env 파일을 요구하는 이상한 요청이었습니다.
그러나 중요한 설정 정보가 담길 법한 파일을 노리고 있다는 점에서 명백히 악의적인 목적을 가진 요청으로 보였습니다.
하지만 더 이상한 점이 있었습니다. Issuefy의 WebServer와 WAS는 ALB를 통해서만 접근할 수 있도록 보안 그룹이 설정되어 있었습니다. 따라서 로그에 찍힌 43.203.xx.x라는 IP로는 직접 접근이 불가능했고, IP는 서버의 IP도 아니었습니다. 게다가 ALB의 도메인은 외부에 노출한 적이 없었고 설령 노출되었다 하더라도 요청 URL에는 IP가 아닌 도메인이 찍혀야 정상이었을 것입니다.
Request routing
Before a client sends a request to your load balancer, it resolves the load balancer's domain name using a Domain Name System (DNS) server. The DNS entry is controlled by Amazon, because your load balancers are in the amazonaws.com domain. The Amazon DNS servers return one or more IP addresses to the client. These are the IP addresses of the load balancer nodes for your load balancer. With Network Load Balancers, Elastic Load Balancing creates a network interface for each Availability Zone that you enable, and uses it to get a static IP address. You can optionally associate one Elastic IP address with each network interface when you create the Network Load Balancer.
이 의문을 해결하기 위해 AWS ALB의 동작 방식을 공식 문서에서 확인해 보았습니다.
그 결과 ALB는 클라이언트에게 ALB 노드의 IP를 전달한다는 사실을 알게 되었습니다.
하지만 여전히 의문이 남았습니다. AWS에서 관리하는 ALB의 IP를 어떻게 알아냈을까요?
이에 대한 답 역시 공식 문서에서 찾을 수 있었습니다.
AWS는 자신들이 호스팅하는 IP의 주소 범위를 일정 부분 공개하고 있습니다.
로그에 찍힌 43.203.xx.x는 Issuefy 서버의 IP가 아니라 AWS에서 관리하는 ALB의 IP였습니다.
ALB를 통해 Issuefy 서버에 접근할 수 있었기에, 서버의 실제 IP가 아님에도 불구하고 이런 일이 발생할 수 있었던 것입니다. 누군가 ALB의 IP 대역에 무차별적인 요청을 보내고 있었던 것입니다.
이는 '포트 스캐닝'이라는 공격 기법인데, 공격자는 AWS와 같은 클라우드 서비스의 IP 대역을 파악한 뒤, 해당 대역에 무작위로 요청을 보내 응답이 오는 서버를 찾아냅니다. 이렇게 찾아낸 서버를 대상으로 각종 취약점을 노리는 URL을 시도하며 정보를 탈취하려 하는 것입니다.
만약 Issuefy 서버에 취약점이 있었다면 중요한 정보가 유출되는 등 심각한 피해를 입었을 수도 있는 상황이었습니다.
과거 로그를 자세히 살펴보니 보니 이런 시도가 간헐적으로 발생해 왔음을 확인할 수 있었습니다.
대응
먼저 ALB의 리스너 규칙을 수정하여 Issuefy 서버로의 직접 접근을 차단하기로 했습니다.
ALB의 IP나 DNS로는 API 서버에 접근할 수 없고, 오직 정해진 도메인을 통해서만 접근할 수 있도록 제한한 것입니다.
Issuefy는 80포트로 들어오는 HTTP 요청을 443 포트의 HTTPS로 리디렉션 하고 있습니다.
따라서 443 포트의 리스너 규칙을 다음과 같이 추가했습니다.
- 호스트 헤더가 허용된 도메인이 아닌 경우 HTTP 401 Unauthorized 응답을 반환한다.
- 허용된 도메인으로 요청이 오면 기존 규칙에 따라 처리한다.
이렇게 ALB 단에서 의심스러운 요청을 사전에 차단함으로써 Issuefy 서버까지 도달하지 못하도록 했습니다.
규칙을 적용하고 며칠간 로그를 모니터링 한 결과, 더 이상 포트 스캐닝을 시도하는 요청은 관측되지 않았습니다.
개선점
그렇다면 이제 위협에서 안전해졌다고 볼 수 있을까요?
아직은 아니라고 생각합니다.
ALB 리스너 규칙을 수정하여 허용된 도메인으로만 접근을 제한했지만, 여전히 이 도메인을 통해 부적절한 요청이 들어올 가능성은 존재합니다. 물론 인증 필터에서 이러한 요청을 걸러낼 수 있겠지만, 지속적인 공격 시도 자체가 서버에 부담을 줄 수 있는 위협입니다.
이를 보완하기 위한 방안으로 고려해 볼 수 있는 것이 ALB 단에서의 IP 차단입니다. 일정 시간 내에 동일한 IP에서 인증되지 않은 요청이 반복적으로 들어오는 경우, 해당 IP를 일정 시간 동안 차단하는 규칙을 설정하는 것입니다. 한걸음 더 나아가 WAF를 ALB 앞단에 배치하는 것도 방법이 될 수 있다고 생각합니다. 다만 이러한 솔루션의 도입에는 추가적인 학습, 비용, 시간이 소요되므로 팀 내에서 충분한 논의를 거쳐 우선순위를 결정하고 단계적으로 적용해 나가려 합니다.
한편, Issuefy의 CI/CD 파이프라인에도 개선이 필요한 부분이 있습니다. 현재는 애플리케이션 설정 정보를 서브모듈로 관리하고 있는데, 배포 시에 이 파일을 복사하여 사용하고 있습니다. 그런데 이 과정에서 설정 파일이 외부로 유출될 위험이 있습니다.
이 문제를 해결하기 위해, 설정 파일 자체를 암호화하고 배포 시에 복호화 키를 환경 변수로 전달하는 방식으로 전환할 계획입니다. 이렇게 하면 설정 파일이 유출되더라도, 복호화 키가 없으면 파일의 내용을 확인할 수 없게 되므로 보안성이 조금 더 높아질 것이라고 생각합니다.
'Issuefy' 카테고리의 다른 글
[Issuefy] Jmeter를 사용한 성능 테스트 및 스케일링 분석 (0) | 2024.09.23 |
---|---|
[Issuefy] Server-Sent Events를 이용한 실시간 알림 기능 도입기 (4) | 2024.09.13 |
[Issuefy]Loki와 LogQL을 활용한 실시간 사용자 활동 대시보드 구현 (2) | 2024.09.05 |
[Issuefy] 통합 모니터링 도입기 (2) | 2024.06.05 |