진행중이던 프로젝트를 하면서 로그인 회원가입 UI를 짜고 서버와 연결을 하려고 했는데 계속 해서 뜨는 CORS 정말정말 며칠을 이거 때문에 고생했다.....
🚫CORS란?
CORS(Cross-Origin Resource Sharing)는 출처가 다른 자원들을 공유한다는 뜻으로, 한 출처에 있는 자원에서 다른 출처에 있는 자원에 접근하도록 하는 개념이다. 직역하면, 교차되는 출처 자원들의 공유이다. 다른 출처에 있는 자원을 요청한다고 하면, 이를 교차 출처 요청이라고 부른다.
여기서 나온 origin 출처는 무엇일까?
Origin은 URL에서 프로토콜, 호스트(도메), 포트 번호를 합친 부분을 의미한다. 3가지가 같으면 동일 출처(Origin)라고 한다.
✅ http or https → 프로토콜
✅ naver.com → 호스트
✅ :80 or :81 or :443 → 포트번호
기억하자!
🚫SOP란?
SOP를 소개하는 이유는, SOP가 CORS와 아주 긴밀한 관계를 가지고 있기 때문이다.
SOP(Same Origin Policy)는 다른 Origin으로 요청을 보낼 수 없도록 금지하는 브라우저의 기본적인 보안 정책이다. 즉, 동일한 Origin으로만 요청을 보낼 수 있게 하는 것이다. 실제로 아주 옛날에는 이것이 절대적인 규칙이었기 때문에, 다른 Origin으로 요청을 보내는 건 애초에 불가능하였다. 그러나 기술이 발달하면서 서로 다른 Origin끼리 데이터를 주고받아야 하는 일이 많아졌고, 이로 인해 SOP는 별도의 예외 사항을 두게 되었다. 즉, 몇 가지 예외 상황에 대해서는 다른 Origin으로도 요청을 보낼 수 있게 하는 것이다.
CORS(Cross Origin Resource Sharing)는 다른 Origin으로 요청을 보내기 위해 지켜야 하는 정책으로, 원래대로라면 SOP에 의해 막히게 될 요청을 풀어주는 정책이라고 볼 수 있다. 하도 우리를 짜증 나게 해서 요청을 막는 정책인 줄 알았더니, 오히려 요청을 보낼 수 있도록 돕는 정책이었던 것이다.
🚫CORS동작원리
- 브라우저는 HTTP 요청을 보낸다.
- 서버는 요청에 대한 응답을 반환한다.
- 브라우저는 응답을 분석하여 CORS 헤더를 확인한다.
- CORS 헤더가 존재하면 브라우저는 자원에 대한 권한을 검사한다.
- 권한이 허용되면 자원을 사용하고, 그렇지 않으면 에러가 발생한다.
CORS의 기본적인 동작 원리는 단순하다. 브라우저는 다른 Origin으로 요청을 보낼 때 Origin 헤더에 자신의 Origin을 설정하고, 서버로부터 응답을 받으면 응답의 Access-Control-Allow-Origin 헤더에 설정된 Origin의 목록에 요청의 Origin 헤더 값이 포함되는지 검사하는 것뿐이다. 즉, CORS 요청을 위해서는 서버에서 응답의 Access-Control-Allow-Origin 헤더에 허용되는 Origin의 목록 혹은 와일드카드(*)를 설정해주면 된다. 이것이 기본적인 CORS 정책이다.
여기서 CORS동작원리는 총 3가지가 있다.
1.Simple Request (단순 요청)
예비 요청을 보내지 않고 바로 서버에게 본 요청을 전달한다. 서버가 이에 대한 응답으로 헤더에 Access-Control-Allow-Origin 값을 보내주면 브라우저가 CORS 정책 위반 여부를 검사한다.
2.Preflighted Request (사전 요청)
브라우저는 요청을 한번에 보내지 않고 예비 요청과 본 요청으로 나누어서 서버로 전송한다.
OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인한다.
< cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송(preflighted)하는 것 >
이 때 앞에 예비 요청이 포함 될 뿐 CORS 에러는 예비 요청의 성공여부와는 별 상관이 없다. 브라우저가 CORS 여부를 판단하는 시점은 예비 요청의 응답을 받은 이후이기 때문이다.
예비 요청 자체가 실패해도 CORS 정책 위반으로 처리 될 수 있지만 중요한 것은 예비 요청의 성공/실패여부가 아니라
'응답 헤더에 유효한 Access-Control-Allow-Origin이 있는가'
이다. 그래서 예비 요청이 실패해서 성공 코드가 아니더라도 헤더에 저 값이 제대로 들어가있다면 CORS 정책 위반이 아니라는 의미이다.
3.Credentialed Requests (인증 정보를 포함한 요청)
Credentialed Requests는 HTTP cookies 와 HTTP Authentication 정보를 인식한다.
기본적으로 cross-site XMLHttpRequest 나 Fetch 호출에서, 브라우저는 자격 증명을 보내지 않는다. (민감한 정보이기 때문) 이때 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션이다.
3가지의 옵션이 들어갈 수 있으며 각 값들의 가지는 의미는 아래와 같다.
same-origin (기본값) : 같은 출처 간 요청에만 인증 정보를 담을 수 있다.
include : 모든 요청에 인증 정보를 담을 수 있다.
omit : 모든 요청에 인증 정보를 담지 않는다.
만약 same-origin이나 include 와 같은 옵션을 사용하여 리소스 요청에 인증 정보가 포함된다면, 이제 브라우저는 다른 출처의 리소스를 요청할 때 단순히 Access-Control-Allow-Origin 만 확인하는 것이 아니라 좀 더 빡빡한 검사 조건을 추가하게 된다.
참고자료
'프로젝트 > APMA' 카테고리의 다른 글
기존 프로젝트 업그레이드 시키기 (0) | 2023.12.09 |
---|---|
Ajax란 무엇인가? (feat. success와 done의 차이) (0) | 2023.08.11 |