CloudFront + S3 + API Gateway 구성의 웹 애플리케이션에서 CORS 에러 회피하기

2023.01.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

안녕하세요, 클래스메서드 CX사업본부 Delivery부의 정현재입니다.

이번 블로그에서는 제가 CloudFront, S3, API Gateway를 사용하여 웹 애플리케이션을 구축했을 때 발생했던 CORS 문제에 대해 이야기 해보려 합니다.

처음에 저는 위와 같이 S3에서 React 애플리케이션을 호스팅 한 후, CloudFront를 경유하여 접근할 수 있도록 하였습니다. 그리고 Lambda와 함께 API Gateway REST API 를 구축하여 React 애플리케이션으로부터 오는 요청을 처리하도록 하였습니다. 구축이 제대로 되었는지 테스트를 하기 위해 React 애플리케이션에 버튼 하나를 배치하여 클릭을 하면 API Gateway로 axios 요청을 보내는 작업을 해보았습니다.

다음과 같이 CORS 에러가 발생하였습니다.

CORS란?

CORS를 풀어 쓰면 Cross-Origin Resource Sharing으로, 어떠한 한 도메인의 자원에서 다른 도메인의 자원에 접근하는 것을 말합니다. 개인정보와 같은 중요한 정보를 다른 사이트로 전송하는 등 악용될 가능성이 있기 때문에 보안상의 문제로 브라우저에서는 기본적으로 이를 차단하고 있습니다. 위에서 저의 경우에는 CloudFront의 도메인에서 API Gateway의 도메인으로 요청을 보냈기 때문에 브라우저에서 이를 차단하면서 CORS 에러가 발생하게 되었습니다. 다른 도메인의 API에 접근하기 위해서는 명시적으로 API 측에 CORS를 허용하도록 하는 작업이 필요합니다.

CORS 에러 방지

API Gateway의 경우 콘솔을 이용하여 CORS 활성화를 하는 것으로 OPTIONS 메서드 정의, 통합 응답(Integration Response)에 필요한 응답 헤더를 추가하는 작업이 자동으로 되기 때문에 매우 편리합니다.

하지만 만약 API Gateway의 백엔드로서 Lambda Proxy를 사용하고 있는 경우에는 통합 응답이 반환되지 않기 때문에 설정이 불가능합니다. 한다고 하면, OPTIONS 메서드를 정의하고 백엔드에서 수동으로 필요한 응답 헤더를 추가하는 작업이 필요합니다. 매우 귀찮을 수 있습니다.. 이럴 때 생각할 수 있는 다른 방법이 있습니다.

CORS 에러는 서로 다른 도메인의 자원에 접근하려 할 때 발생

그 말은 즉, 도메인이 일치하게 된다면 CORS 에러가 발생하지 않는다는 말이 됩니다. API Gateway의 엔드포인트를 CloudFront의 오리진으로 설정을 한다면 한 도메인만을 사용하여 API에 접근할 수 있기 때문에 CORS 에러를 피할 수 있습니다.

API Gateway + CloudFront 구성하기

다음과 같이 구성을 하게 된다면 하나의 도메인을 사용하여 웹 사이트 호스팅, API Gateway를 통한 API 접근이 모두 가능해집니다. 설정 방법도 간단합니다.

API Gateway 콘솔의 스테이지 탭에서 다음과 같이 API Gateway의 엔드포인트를 구할 수 있습니다.(API Gateway의 API 경로는 라우팅을 위해 /api/*로 설정하도록 합니다)

CloudFront 콘솔로 이동 후, S3와 연결되어 있는 CloudFront Distribution에서 Origin을 추가합니다. 여기서 아래의 항목을 주의하여 작성하도록 합니다.

  • Origin 도메인은 API Gateway의 엔드포인트에서 스테이지명을 뺀 도메인으로 입력해야합니다.
  • API Gateway는 HTTPS 통신만 지원하기 때문에 HTTPS만 허용을 선택해야합니다.
  • Origin 경로는 스테이지명을 입력합니다.(선택사항)
    • Origin 경로에 스테이지명을 입력하는 경우 Behavior 작성 시, 경로 패턴에 스테이지명을 입력하지 말아야합니다. 또한, axios 요청에서도 스테이지명을 요청 url에 포함하면 안됩니다.
    • Origin 경로에 스테이지명을 입력하지 않는 경우 Behavior 작성 시, 경로 패턴에 스테이지명까지 입력을 하여야합니다. 또한, axios 요청에서도 스테이지명을 요청 url에 포함하여야합니다.

그 후, Behavior을 작성하여 /api/* 의 경로의 요청은 API Gateway에 액세스를 하도록 설정을 합니다. 저는 Origin 작성 시, Origin 경로에 스테이지명을 설정했기 때문에 경로 패턴을 스테이지명을 뺀 /api/*로 하고 있습니다. Origin 및 Origin 그룹에는 방금 작성한 API Gateway의 오리진을 선택합니다. 뷰어 프로토콜 정책에서는 항상 HTTPS를 받을 수 있도록 Redirect HTTP to HTTPS로 설정합니다. 나머지 각종 설정들은 필요에 따라 수정하시기 바랍니다.

CloudFront의 설정은 이것으로 끝입니다. API Gateway의 API 경로 변경 및 디플로이, axios 요청 url 변경 등을 필요에 따라 작업하고 다시 axios 요청을 테스트 해보면 정상적으로 요청이 전송되는 것을 확인할 수 있을 것입니다.

마무리

이번 블로그에서는 CloudFront, S3, API Gateway 구성의 애플리케이션에서 CORS를 명시적으로 허용하는 설정을 하는 대신, 도메인을 같게 하여 회피하는 내용을 적어보았습니다. 블로그를 정리하면서 CORS 설정에서 특정 도메인을 허용하도록 제대로 설정을 하면 괜찮지만 *를 사용해 모든 도메인을 허용하도록 하는 설정을 할 것 같으면 이와 같이 도메인을 같게 하여 회피하는 방법이 보안상으로 더 좋을 것 같다는 생각이 들었습니다. 저와 같은 구성으로 애플리케이션의 구축을 생각하시고 계신 분들께 도움이 되었으면 좋겠습니다!