Day 14 : 사공이 많으면 배가 산으로 간다, Lambda + Express 에서 CORS 처리하는 법

2023. 6. 19. 11:22International Sign Lang 프로젝트/백엔드

728x90
 

Day 13 : ??? : 나 serverless deploy 쳐본 사람이야

Day 12-1 CSRF 와 CORS 는 매우 연관이 깊다?! Day 11 : 싸우자 해커야! CSRF, HttpOnly, CSP 대응하기 Day 10 : MySQL2 오류, "Client does not support authentication protocol requested by server" 해결 방법 Day 9 : 에러나면 손모가

xpmxf4.tistory.com

위 글을 보고 오시는 것을 추천드립니다!


1. 오늘의 주제

오늘은 Lambda 함수에서의 CORS 처리를 하는 법에 대해서

저의 에러를 통해 알아보겠습니다!

 

저번 글까지 저는 저의 Express를 Serverless-http 라이브러리를 통해

람다 함수로 Wrapping 하고, 이를 Serverless 프레임워크로 

저의 AWS 계정에다가 배포를 하였습니다!

 

저번에 배포를 하고 나서 오늘 Lambda 에 배포된 api 들을 테스트 해봤는 데

제대로 돌아가지가 않습니다...

어째서일까?

2. 원인 분석

ㅗㅜㅗㅜ 말을 안해붜렸쒀

제가 저번에 깜빡하고 말씀을 안 드린게 있었더라고요 ㅠ

람다 함수를 배포하고 나서 aws 관련 문서들을 읽다 다음 문서를 읽게 되었는데요,

 

REST API 리소스에 대한 CORS 활성화 - Amazon API Gateway

REST API 리소스에 대한 CORS 활성화 CORS(Cross-origin 리소스 공유)는 브라우저에서 실행 중인 스크립트에서 시작되는 cross-origin HTTP 요청을 제한하는 브라우저 보안 기능입니다. REST API의 리소스가 비

docs.aws.amazon.com

Lambda 또는 HTTP 비 프록시 통합 및 AWS 서비스 통합을 위해 CORS 지원 활성화
Lambda 사용자 지정(비 프록시) 통합, HTTP 사용자 지정(비 프록시) 통합 또는 AWS 서비스 통합의 경우,
API Gateway 메서드 응답 및 통합 응답 설정을 사용하여 필요한 헤더를 설정할 수 있습니다.

AWS Management Console을 사용하여 CORS를 활성화하는 경우
API Gateway에서 OPTIONS 메서드를 생성하고 기존 메서드 통합 응답에 
Access-Control-Allow-Origin 헤더를 추가하려고 시도합니다.

항상 이를 수행하는 것은 아니므로 경우에 따라 통합 응답을 수동으로 수정하여 CORS를 적절하게 활성화해야 합니다.
일반적으로 이 작업은 Access-Control-Allow-Origin 헤더를 반환하기 위해 통합 응답을 수동으로 수정하는 것입니다.

저는 위 설명에서 볼드체로 된 가운데 부분'만' 보고 이렇게 생각했습니다.

 

아 람다 함수는 따로 Express 에서는
API Gateway 에서 CORS 활성화를 해야 하는구나?

그러면 기존의 Express의 app.js 파일 안에 있는
app.use(cors()) 에다가 API Gateway에서의 CORS 활성화를
하면 더 보안이 좋아지겠네? 

 

그래서 바로 호다닥 API Gateway에서 CORS 처리를 하도록 만들었죠!

하지만 오늘 테스트를 하니 전혀 되지를 않던 것...

엉엉엉엉ㅇ어어ㅓ어어엉

왜 안될까 하다가 위 의문에 대해 다시 생각해 봤습니다.

CORS에 대한 처리가 API Gateway, Express
2 곳에서 이중으로 되어 있어 오히려 문제이지 않을까?

왜냐하면 이게 신기하게 20번 테스트하면 

1, 2번 정도는 CORS 에러가 나타나지 않고

의도한 대로 작동을 했었기 때문이죠,,,

 

그래서 API Gateway에서 CORS 처리를 없애니깐

API 가 정말 정상적으로 작동을 하게 되었다,,,

하지만 아직도 뭔가 왜 되고, 왜 안 되는지에 스스로 명확하게 이해가 되지 않아

좀 더 자세하게 알아봐야겠다는 생각에 다다랐다.

3. CORS에 대해 다시 한번 복습해 보자

먼저 다시 한번 CORS에 대해 복습해 보자!

교차 출처 리소스 공유 표준(CORS)은 웹 브라우저에서 해당 정보를 읽는 것이
허용된 출처를 서버에서 설명할 수 있는 새로운 HTTP 헤더를 추가함으로써 동작합니다.

추가적으로, 서버 데이터에 부수 효과(side effect)를 일으킬 수 있는
HTTP 요청 메서드(GET을 제외한 HTTP 메서드)에 대해,
CORS 명세는 브라우저가 요청을 OPTIONS 메서드로 "프리플라이트"(preflight, 사전 전달)하여
지원하는 메서드를 요청하고, 서버의 "허가"가 떨어지면 실제 요청을 보내도록 요구하고 있습니다.

또한 서버는 클라이언트에게 요청에 "인증정보"(쿠키, HTTP 인증)를 함께 보내야 한다고 알려줄 수도 있습니다.

CORS의 핵심 컨셉은 다음과 같습니다.

브라우저(프론트엔드)가 다른 원본의 리소스에 액세스를 시도할 때, 
그 리소스의 서버(백엔드) 에게 다음과 같이 물어봅니다.

"너의 리로스를 가지고 싶어. 너와 나의 원본(도메인)은 다르지만, 나의 엑세스를 허용해 주겠니?"
그리고 서버는 이에 대한 대답으로 HTTP 헤더의 여러 필드를 통해 답하게 됩니다.
Access-Control-* 등의 헤더를 통해 말이죠.

이런 CORS 메커니즘을 통해, 웹 사이트는 악의적인 상호작용을 통해 

사용자의 데이터를 탈취하는 것을 방지하며, 다른 원본으로부터 안전하게 리소스를 공유할 있습니다.

4. 대충 알겠는 데, 단순 헤더만 추가하면 끝나는 거 아니야?

라는 생각을 했었죠 하하하

진짜 빠따쳐야 겠다 내 자신,,,

이제 이 상황을 AWS API Gateway와 Express.js에서 CORS를 모두 설정한 상황에 대입해 보겠습니다.

 

AWS API Gateway와 Express.js(Lambda) 모두에서 CORS를 설정하면,

두 시스템이 모두 CORS 관련 헤더를 처리하려고 시도합니다.

하지만 이 둘은 엄연히 서로 독립적으로 작동하며, 각자의 CORS 설정에 따라 헤더를 처리합니다.

 

이렇게 되면, API Gateway와 Express.js 간에 헤더 처리에 차이가 있을 수 있습니다.

예를 들어, API Gateway가 CORS를 허용하더라도 Express.js가 해당 출처를 허용하지 않으면, 요청은 실패하게 됩니다.

 

또한, API Gateway와 Express.js 둘 다 CORS 헤더를 추가하려고 시도할 때,

둘 중 하나가 먼저 헤더를 추가하고, 다른 하나가 그것을 덮어쓰려고 시도할 수 있습니다.

이렇게 되면 어떤 CORS 헤더가 최종 응답에 포함될지는 실행 순서나 타이밍에 따라 달라지게 됩니다.

이런 중복 설정 CORS 정책 위반을 초래해 저의 api처럼

20번 중에 1, 2번은 정상적인 것처럼 동작하는 기괴한 형태가 되는 거죠!

5. 위 aws 문서처럼 API Gateway에서 일괄적으로 처리하면 안 돼?

사실 API Gateway에서 일괄적으로 처리하는 게 더 일반적이긴 합니다.

하지만 저는 Lambda 각자에서 CORS 처리를 하도록 설정을 했죠.

그 이유는 일관성에 있습니다!

API Gateway에서 CORS 설정을 관리하면, 모든 Lambda 함수에 일관된 CORS 정책을 적용 있습니다.

이렇게 하면 CORS 설정을 중앙에서 관리할 있어 관리가 용이하게 되겠죠!

 

하지만, API Gateway에서는 요청에 대해 동적으로 CORS 헤더를 변경하는 것이 어렵습니다.

MDN 문서를 보신 분들이라면 알겠지만 CORS 정책상

side-effect를 일으킬만한 서버의 리소스에 직접적으로 접근하는 경우 preflight 를 통해서

먼저 접근 가능 여부에 대해 서버에게서 응답을 받아야 합니다.

 

하지만 굳이 그럴 필요가 없는 리소스들도 존재합니다.

예를 들면 블로그 측면에 표시되는 오늘 하루 방문자 수 같은 경우,

보안이 중요하지도 않고 서버에 side-effect를 남기지도 않으니

굳이 CORS 처리를 할 필요가 없죠.

 

 

그러면 API Gateway에서 CORS 처리하는 건 별로겠네요?

항상 그렇지만, 기술에 절대는 없습니다. 상황에 따라 장점이 더 부각될 수도, 안 될 수도 있기 때문에요.

따라서 어떤 방식을 사용할지는 애플리케이션의 요구 사항과 특성에 따라 결정해야 합니다.

 

만약 요청에 대해 동적으로 CORS 정책을 변경해야 하는 경우에는

Express.js cors 미들웨어를 사용하는 것이 적합할 있습니다.

반면에 모든 Lambda 함수에 대해 일관된 CORS 정책을 적용하고 싶다면,

API Gateway에서 CORS 처리하는 것이 효율적일 있을 것입니다.

 

지금까지의 저의 설계에서는 사실 API Gateway로 일괄 처리하는 게 더 좋지만

저는 추후 Lambda에서 다른 기능을 하는 람다들을 더 배포를 할 생각에

각자 람다(Express)에서 처리하도록 한 것이니, 여러분도 고민하시고 결정하시면 좋을 거 같아요!

오늘의 결론이자 TIL

CORS 처리는 꼭 한 곳에서만 하자!

참고

 

교차 출처 리소스 공유 (CORS) - HTTP | MDN

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라

developer.mozilla.org

마무리

언제나 피드백은 환영입니다!

 

GitHub - xpmxf4/ISL_FrontEnd

Contribute to xpmxf4/ISL_FrontEnd development by creating an account on GitHub.

github.com

 

 

GitHub - xpmxf4/ISL_BackEnd

Contribute to xpmxf4/ISL_BackEnd development by creating an account on GitHub.

github.com

만약 보신다면 스타도...! ㅎㅎ

728x90