AS-IS
- 현재 모든 서버 요소들이 0.0.0.0/0 으로 열려있고 구조화되어있지 않다.
TO-BE
- 서버에 들어오는 요청을 제한하여 DDos 와 같은 공격을 막는다.
기존 계획
- 현재 프론트는 S3 에 올려둔 정적 사이트를 원본으로하여 Cloud Front 에 연결해두었다. 그래서 그 페이지에서 오는 요청만 서버에 접속 할 수 있도록 제한한다.
- 이를 위해 aaa.aaa.ai 도메인을 alb 와 연결하고 alb 의 인바운드 규칙을 현재 사용하고 있는 Cloud Front 접두사 목록으로 제한한다.
- Cloud Front 접두사 목록이란. AWS 에서 관리하는 Cloud Front IP 주소 목록이며 Cloud Front IP 주소는 특정할 수 없고 주기적으로 바뀌기 때문에 AWS 에서 제공하는 접두사 목록(prefix) 를 사용한다.
- 이를 통해 ALB로 들어오는 요청을 프론트로 제한한다.
발생한 문제점
하지만 ALB의 보안그룹 인바운드 규칙을 cloud front 로 제한했을 때 계속 타임아웃이 나는 등 인바운드 규칙이 막혔다. 그래서 AWS Supports 에 사례를 생성해 여쭤봤다. 회신 받은 내용은 다음과 같다.
- S3+CF으로 배포 된 프론트에서 ALB 로 요청을 보낸다고 해도 이게 CF 에서 요청이 가는게 아니라 브라우저 (= 사용자가 접속한 ip) 에서 요청을 보내는거다. 따라서 보안그룹 인바운드 규칙을 CF 으로 제한하면 안되는게 당연하다. Cloud Front 를 거쳐서 오는게 아니니까!
- 이렇게 인바운드 규칙을 CF로 제한하고 싶다면 도메인과 ALB 사이에 CF를 둘 수 있다.
- 기존 [클라이언트 → 도메인 → ALB] 의 구성에서 [클라이언트 → 도메인 → CF → ALB] 으로 변경하는 것이다.
- 하지만 이렇게 도메인에 CF를 연동한다면 도메인을 알고있는 모든 사용자가 우리 서버에 접속 할 수 있게된다. 그렇다면 요청 송/수신 사이에 사용자 정의 헤더 검증을 추가해 요청을 제한할 수 있다. (요청하는 CF와 요청받는 ALB의 리스너 규칙에 사용자 정의 헤더를 추가하여)
-
그래서 프론트의 CF에 사용자 헤더를 추가하고 ALB의 리스너 규칙에 사용자 헤더 검증 로직을 추가했다. 이렇게 했더니 CORS 에러가 났다.
-
이렇게 하면 안된다! 먼저, 웹 페이지에서 aaa.aaa.ai 에 요청을 보냈을 때 preflight 로 보내는데 그것에 대해 403 이 뜬다. CF를 통해 전달된 요청이 아닌 이전처럼 사용자가 접속한 ip 에서 ALB 로 직접 요청된 것으로 ALB 에 보안 헤더가 존재하지 않는다.
-
[프론트 CF + 도메인 + 백엔드 CF + alb] + 헤더 검증 을 해도 요청은 End User에서 오는 것이고 결국 프론트 cf 에 설정해둔 사용자 정의 헤더가 붙여지지 않는다. 그대로 End User이다. 그래서 헤더가 일치하지 않고, Origin 헤더가 없어 CORS 발생? 근데 또 이게 Cloud Front 에서 발생한 CORS 가 아니었기 때문에 확인할 수 없다.. 정말 이게 가능하게 하려면 …………… SAA의 조언이 필요하다는 AWS Supports 의 의견이 있었다. 구조적으로 옳지 않다는 의견을 2번이나 받았다 ..
-
End User에 대한 이해가 부족했다 …. 브라우저의 동작 과정 !!!!!!!
=================================
[Summary]
문의 사항 : CloudFront를 통해 Origin에 요청 전달시 CORS 에러 발생으로 이에 대한 분석
분석 사항
- CORS Error는 CORS Preflight 요청시 Origin(ALB)에서 403 응답 전달
- CORS Preflight 요청은 CloudFront를 통해 전달된 요청이 아닌 End User -> ALB로 직접 요청이 전달된 건으로 ALB에 설정된 보안 헤더가 존재하지 않아 이에 대해 403 응답 수신
안내 사항
- Origin(ALB)에서 403 Access Denied가 아닌 200 OK와 함께 적절한 CORS Preflight 응답 헤더가 포함되어 있어야 CORS 요청이 정상적으로 처리 될 수 있습니다
- 원하는 CORS 요청 시나리오가 "현재 구성된 아키텍쳐"에서 지원 할 수 없으므로 이에 대해 전문적인 도움 받을 수 있도록 담당 세일즈를 통해 SA의 도움 받으실것을 권고 드렸습니다.
- 따라서 ?????
- 그래서 CORS 처리로 막을 수 있을 것이라 생각했다. CORS는 브라우저에서 요청의 원본을 비교하기위해 서버에 preflight 를 날리는 것으로 브라우저에서 보내는 요청의 헤더값에 지정된 값을 넣어서 보낸다. 이러한 헤더값을 서버에서 검증해서 요청에 대한 응답을 보낸다.
- 기존에는 CORS를 뚫는것에 집중헀지 CORS를 활용할 생각을 못했다.
- 그래서 프론트가 배포한 CDN 주소만 서버에서 CORS를 허용하여 나머지 요청을 제한하려 했다.
- 하지만 브라우저에서 aaa.aaa.ai 를 그냥 접속 했을 때 요청이 허가됐다.
결론
- 결론적으로 CF + ALB 를 이용하여 서버에 오는 요청을 프론트로만 제한하기는 힘들다.
- 프론트에 띄워져있다 하더라도 End User 는 접속한 ip 이다?
- referer 헤더 검증을 통해 가능했을까?
- 그래서 네이버의 메인 페이지를 뜯어보았다. 개발자 모드를 이용해 네이버 api 도메인 주소를 알 수 있었고, 이것을 그냥 접속했을 때 요청 값을 볼 수 있었다. 따라서 다른 회사들도 api 도메인 주소에 그냥 접속할 수 있음을 알았다
- 근데 ip주소는 접속할 수 없었음. 방화벽으로 막아둔걸까?
- [프론트 → 도메인 → ALB] 의 요청 로직을 갖고 ALB 앞에 WAF를 붙인다.
- 국가 기반의 IP 차단, 속도 기반의 IP 차단 , Http Header 기반의 요청 차단 , DDoS 공격 형태의 Flooding 차단, PHP 애플리케이션 공격 차단 등 을 적용했다.
- AWS 에서 기본으로 제공하는 Rule 도 있고 Market space 에서 벤더 사의 솔루션을 사용할 수도 있다.
- CORS 처리를 통해서도 막을수는 없었다.
- 이에 따라 서버의 중요한 요소 (DB,EC2) 등을 private subnet에 배치해 보안을 강화하고 서버에 들어오는 요청을 제한한다.
회고
- End User에 대한 이해가 부족했다 ….
- 브라우저와 서버간의 요청 로직에 대한 이해가 부족했다. CF에 띄워두면 프론트의 요청이 CF에서 오는 줄 알았는데 CF는 S3를 원본으로 하여 CDN 을 띄워준 것이다. 전혀 관련이 없다. CF를 거쳐야 CF에서 오는 요청이 된다.
- WAF에 대해 더 일찍 찾아봤다면 일찍부터 적용했을텐데
WAF 관련 레퍼런스
https://velog.io/@woodonggyu/Getting-started-with-AWS-WAF
https://sh-t.tistory.com/98
https://omoknooni.tistory.com/57