Same Origin Policy(동일 출처 정책)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리해, 공격받을 수 있는 경로를 줄입니다.
❓ 동일 출처(same origin)란 무엇일까 ?
👉 URL의 Protocol, Host, Port를 통해 같은 출처인지 다른 출처인지 판단할 수 있다.
❓ http://localhost 와 동일 출처인 것은 ?
1. https://localhost
2. http://localhost:80
3. http://127.0.0.1
4. http://localhost/api/cors
👉 2번, 4번
1번 : 프로토콜이 다름
2번 : http의 기본포트는 80
3번 : string value가 다르기 때문에 브라우저가 다른 출처로 인식
4번 : /api/cors는 location이므로 동일출처
✔ http의 기본 포트 : 80 , https의 기본 포트 : 443
❓ 다른 출처의 리소스가 필요할때는 어떻게 해야할까 ?
👉 다른 출처의 자원과의 상호 작용을 위해 SOP 예외 조건으로 CORS 정책이 생겼다. CORS 정책을 위반하지 않는 다면 다른 출처의 리소스를 공유할 수 있다.
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.
❓ 어떻게 CORS 정책을 위반했는지 판단할까?
👉 출처를 비교하는 로직은 서버가 아닌 브라우저에 구현되어 있다.
CORS 정책에 위반하는 리소스 요청을 하면 서버가 같은 출처만 받겠다는 로직이 있는 경우가 아니면 서버는 정상적인 응답을 하고,
이후 브라우저가 응답 헤더를 분석하여 CORS 정책 위반이라고 판단되면 그 응답을 사용하지 않는다.
preflight는 브라우저가 본 요청을 보내기 전에 보내는 예비 요청을 말하며 HTTP METHOD 중 OPTIONS를 사용한다.
예비 요청은 본 요청을 보내기 전에 브라우저 스스로 안전한 요청인지 확인하는 과정이다.
단순 요청은 서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. 브라우저는 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다.
예비 요청 없이 바로 본 요청을 보내는 경우로 발생 조건이 까다로워 해당 요청이 발생하는 경우는 드물다.
❓ simple request를 하면 한번 요청하고 끝내는데 왜 Preflight request가 필요한 것일까?
👉 CORS를 모르는 서버를 위해 필요하다.
🤷♀️ 예시
👎 CORS설정이 안되어있는 서버와 simple request를 하는 경우
CORS 설정이 없기 때문에 allow-origin이 없음 -> 브라우저는 확인 후 client에게 CORS 에러 발생 -> 만약 클라이언트가 서버에 get같은 요청이 아닌 delete와 같은 요청이었을 경우 서버입장에서 데이터(DB)가 바뀔 수 있음
👍 CORS설정이 안되어있는 서버와 preflight request를 하는 경우
서버에는 allow-origin이 없기 때문에 브라우저는 client에게 CORS 에러를 발생시킴 -> 이것은 사전요청이기 때문에 서버는 어떠한 행동도 따로하지 않는다. -> client는 CORS에러를 받았기 때문에 다음 실제요청을 보내지 않는다. -> 서버는 안전하게 지켜진다.
인증 관련 헤더를 포함할 때 사용하는 요청이다.
클라이언트 측 ➡ credentials : include
fetch(url, {
credentials: 'include', // 요청에 인증과 관련된 정보를 포함하겠다.
});
❗ 단, credentials: include를 사용하면 브라우저는 Access-Control-Allow-Origin: * 처럼 와일드 문자를 허용하지 않게 된다.
서버 측 ➡ Access-Control-Allow-Credentials: true
❗ Access-Control-Allow-Origin에는 *를 사용할 수 없으며, 명시적인 URL이어야한다.