CORS : Cross-Origin Resource Sharing
- SOP로 막힌 다른 출처 간의 리소스 요청을 허용하기 위한 방식이며,
서버가 특정 출처에 대해 리소스 공유를 (클라이언트의 요청을) 선택적으로 허용한다.
예시로 리액트 앱이 3000 포트에서 실행되고 있고, 스프링부트 백엔드 서버가 8080 포트에서 API를 제공한다고 하자.
이때 리액트 앱(브라우저)이 API 요청을 하면, 두 출처(포트 다름)가 다르기 때문에 브라우저의 보안 정책인 SOP에 의해 기본적으로 차단된다.
이 요청을 허용하려면 백엔드 서버가 CORS 설정을 통해 해당 출처(3000포트)를 명시적으로 허용해야 한다.
-작동방식
- 브라우저가 요청 시 Origin 헤더를 함께 보냄
- 서버가 응답에 Access-Control-Allow-Origin 등의 헤더를 포함시켜 허용 여부를 알려줌
-주요 응답 헤더로는 다음이 있음.
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
- Access-Control-Allow-Credentials
// 스프링 설정파일로 Configuration 다음 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**") // 1.
.allowedOrigins("http://localhost:3000") // 2.
.allowedMethods("GET","POST","PUT","DELETE","OPTIONS") // 3.
.allowedHeaders("*") // 4.
.allowCredentials(true); // 5.
}
}
/*
1.어떤 경로에 CORS 허용할지 지정.
"/**"는 모든 경로 (/api/**, /ws/** 등 전부) 를 의미함.
즉, Spring 서버의 모든 API에 대해 CORS 허용하는 설정.
2.어떤 출처의 요청을 허용할지 지정.리액트(3000포트)에서 API요청을 허용.
3.OPTIONS 는 Preflight 요청할 때 사용.
4.요청할 때 허용할 헤더 설정.
예를들어 Authorization, Content-Type, X-Request-With 등
JWT, 쿠키, 커스텀 헤더 를사용하려면 필수.
5."쿠키를 포함한 요청 허용 여부" 를 설정
React에서 fetch나 axios로 withCredentials: true 옵션을 줄 때,
여기서도 이 설정을 true로 해줘야 쿠키가 백엔드에 전달됨.
주의: allowedOrigins("*") 와 allowCredentials(true)는
함께 쓰면 에러 발생함.
→ 쿠키를 허용할 땐, * 대신 정확한 origin을 지정해야 함.
+ allowCredentials(true)를 설정하면 브라우저는 요청에 쿠키와 같은 자격 증명을 포함시킨다.
이 경우, allowedOrigins("*")를 사용할 수 없으며, 명시적으로 허용할 출처를 지정해야 함.
예: allowedOrigins("http://localhost:3000")
*/
위와 같이 CORS 설정을 해주면,
브라우저가 SOP를 우회할 수 있도록 CORS허용한 응답헤더를 다음과 같이 볼 수 있음.
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
SOP : Same-Origin Policy
- 브라우저에서 실행되는 JavaScript 코드가 다른 출처의 리소스에 접근하지 못하도록 제한하는 브라우저 보안 정책.
이는 클라이언트 측 보안 정책으로, 서버 간의 통신에는 적용되지 않는다.
→ 브라우저 안에서만 적용됨, 즉 프론트엔드 JS 코드 ↔ 백엔드 요청 같은 클라이언트-서버 통신에는 적용되고,
→ 서버 ↔ 서버 간 통신 (예: Spring 서버가 외부 API를 호출)에는 적용되지 않는다.
SOP가 적용되는 상황:
SOP가 적용되지 않는 상황:
이건 서버끼리 통신이기 때문에 SOP는 전혀 상관없음. 그냥 통신함.
SOP가 필요한 이유는
→ 악성 스크립트가 사용자의 쿠키/세션을 탈취하지 못하게 하기 위해.
1. SOP가 등장한 배경 (왜 필요한가?)
배경: 보안 위협을 막기 위해
웹은 기본적으로 개방형 플랫폼이다.
서로 다른 웹사이트 간에 리소스를 공유하거나 요청할 수 있다면 편리할 수 있지만, 보안상 매우 위험할 수 있음.
실제로 있었던 보안 이슈:
Cross-Site Request Forgery (CSRF)와 Cross-Site Scripting (XSS)
예시: 쿠키 탈취 시나리오 (SOP가 없다고 가정)
- 사용자가 로그인한 사이트 https://bank.com 에서 인증된 쿠키를 가지고 있음.
- 악성 웹사이트 http://evil.com 에 접속함.
- evil.com 이 <script>로 https://bank.com/api/account 같은 민감한 요청을 자동으로 날림.
- 브라우저는 자동으로 bank.com의 쿠키를 함께 전송함.
- 결과적으로 악성 사이트가 사용자의 계좌 조회나 송금까지 할 수 있음.
SOP는 이런 공격을 막기 위해 "다른 출처의 스크립트 요청은 차단" 하도록 브라우저에 기본 탑재된 보안 정책.
동일 출처의 기준은 다음과 같음
- 프로토콜 (http, https)
- 도메인 (example.com)
- 포트 번호 (80, 3000 등)
프로토콜, 도메인, 포트번호 세 가지 조건을 다 만족시켜야 동일출처로 간주함.
| URL 1 | URL 2 | 같은 출처인가? | 이유 |
| http://example.com:80 | http://example.com:80 | O | 모두 동일 |
| http://example.com | https://example.com | X | 프로토콜 다름 |
| http://example.com | http://example.com:3000 | X | 포트 다름 |
| http://example.com | http://api.example.com | X | 도메인 다름 (서브도메인 포함) |
'정리' 카테고리의 다른 글
| WebSocket (0) | 2025.04.12 |
|---|---|
| OSI 7계층과 존재 이유, TCP/IP 4계층 (0) | 2025.04.11 |
| Https와 SSL HandShake (0) | 2025.04.09 |
| TCP와 UDP (0) | 2025.04.08 |
| URL 입력부터 페이지 렌더링까지 (1) | 2025.04.07 |