HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
📙
백엔드 알아야 할 지식
/
🤿
CORS(Cross Origin Resource Sharing)
🤿

CORS(Cross Origin Resource Sharing)

Same-Origin PolicySOP가 없다면?CORSCORS 흐름1. 예비 요청(pre flight request)과 본 요청2. 단순 요청3. Credentialed 요청CORS 필요성CORS 우회하기1. 프론트엔드에서 Proxy Server(서버의 출처로)를 활용webpack-dev-serverhttp-proxy-middleware (node server 사용시)리액트 CRASpring에서 CORS 허용가능하도록 설정하는법WebMvcConfigurer이용WebSecurityConfigCorsFilter@CrossOrigin 어노테이션 이용테스트 방법Chrome 에서 CORS Disable/Enable

Same-Origin Policy

💡
어떤 출처에서 불러온 리소스(eg.클라이언트 페이지)가 다른 출처(eg. Server)에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 정책. 스크립트에만 적용됨. 웹 브라우저에서 실행되는 자바스크립트 클라이언트에서 원래 코드가 제공된 사이트 외에 다른 사이트에는 접근을 제외하는 규칙임
https://velog.io/@sangmin7648/SOP-CORS란
https://velog.io/@sangmin7648/SOP-CORS란
  • 호스트, 프로토콜, 포트가 같으면 동일한 출처임
  • 어떤 페이지의 악의적인 스크립트가 다른 페이지의 DOM을 통해 데이터에 접근하는 것을 방지함
  • 이미지, CSS같은 리소스는 HTML 태그를 통해 다른 출처여도 접근할 수 있음
  • 사용자를 보호하기 위한 클라이언트 측 정책으로 요청이 들어왔을 때, Same Origin이 아니라면 허용을 안해줌 → 서버 간 통신에는 적용되지 않음

SOP가 없다면?

  • SOP가 없을 때 발생가능한 문제 예
    • 가짜 은행 피싱사이트의 페이지에 iframe으로 진짜 은행 사이트가 로드됐다. iframe 내 진짜 은행 사이트에 로그인 했을 때 가짜 사이트가 간단한 스크립트로 진짜의 DOM 요소에 접근 가능하다. 요청을 조작해 누군가에게 송금하게 하는것도 가능할 수 있다.
    • notion image
    • 출처가 다른 사이트 간 통신은 보안에 취약할 수 밖에 없다
    • 출처가 같으면(eg. 클라이언트의 출처와 서버의 출처가 같으면. 근데 이런경우가 많지 않지) 외부의 공격을 차단할 수 있기에 SOP를 사용함
    • 그러나 웹은 다른 출처의 resource를 가져다쓰는 경우가 많기에 예외 조항으로 CORS를 두고 있음

CORS

💡
HTTP-header 의 정보를 통해 서버가 브라우저에게 리소스 로딩을 할 수 있는 다른 출처를 허용할 수 있게함
notion image
  • 다양한 호스트에 접근하고 다양한 리소스가 필요하다 보니 보안이 중요해짐
  • 클라이언트는 동일한 출처의 리소스에만 접근이 가능함(SOP)
  • 다양한 출처의 리소스에 접근 가능하게 해주는 것이 CORS임
  • 서버 측에서 CORS설정을 해 주었다면 응답 헤더에 Access-Control-Allow-Origin이 설정되어 돌아옴
  • 작동방식 :
    • 1) 클라이언트가 다른 출처의 리소스를 요청할 때 헤더에 Origin 필드에 요청을 보내는 곳(출처)를 함께 보낸다
    • 2) 이후 서버가 응답할 때 응답 헤더의 Access-Control-Allow-Origin 필드에 해당 (서버에 있는)리소스에 접근이 허용된 출처를 보낸다
    • 3) 응답을 받은 클라이언트는(브라우저) 보냈던 요청의 Origin과 응답의 Access-Control-Allow-Origin을 비교해 Origin 이 허용된 곳인지를 확인함
      • 허용되지 않으면 CORS 에러. 허용되면 resource 받을 수 있음

CORS 흐름

1. 예비 요청(pre flight request)과 본 요청

https://velog.io/@sangmin7648/SOP-CORS란
https://velog.io/@sangmin7648/SOP-CORS란
  • 우리가 가장 많이 접하는 요청
  • preflight 요청은 CORS 호환 웹 브라우저와 서버 간에 자바스크립트 클라이언트의 실제 요청이 교차 사이트의 리소스에 접근하기 전 ‘무대 뒤에서’ 발생함. REST API는 CORS 제안인 Access-Control-Allow-Origin HTTP 헤더를 사용해서 리소스에 대한 교차-사이트 접근을 허용하는 사이트를 나열 할 수있음
현재 웹 브라우저의 대부분은 Origin이나 Access-Control-Request-Method 같은 특별한 HTTP 요청 헤더를 보냄으로써 CORS를 지원함
  • Origin 헤더 : 요청 자바스크립트 클라이언트의 스킴/호스트/포트의 소스 위치를 나타냄
  • Access-Control-Request-Method 헤더 : CORS preflight 요청 떄 보내지는데, 클라이언트의 실제 요청에서 어떤 HTTP 요청이 사용되는지를 나타냄
  1. 단순 요청이 아닌 경우 브라우저가 본 요청을 보내기 전 OPTIONS 메서드를 사용해 preflight를 보냄
  1. 서버는 해당 요청에 대해 response를 보내고 브라우저가 해당 Header정보를 확인한 후 허가된 경우에만 본 요청을 넣음
    1. 이 때 서버가 Header에 담은 허가 정보를 확인한 후 어떤 것이 해당이 안되는지 확인을 해야 함
      Access-Control-Allow-Origin : 서버측 허가 출처 Access-Control-Allow-Method : 서버측 허가 메소드 Access-Control-Allow-Headers : 서버측 허가 헤더

2. 단순 요청

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
notion image
  • 서버에서 Allow-Origin 안주면 본요청 fail하게 됨
  1. 브라우저를 거치지 않고 바로 서버로 들어감
  1. 서버에서 온 Response Header를 확인하여 브라우저가 CORS 위반 여부를 가림

3. Credentialed 요청

notion image
  • 서버의 쿠키나 인증과 관련된 정보를 가져오도록 credentials 설정을 바꿀 수 있는데, 이 경우 더 엄격한 CORS 심사를 함
notion image
  • Client가 credentials 옵션을 include로 설정하고 다른 출처의 리소스에 접근할 때, 서버는 모든 출처, 메소드 헤더를 허용하고 있는 상태이면 ⇒ CORS 에러 발생함!
  • credentials가 include인데 서버가 모든 출처, 메소드, 헤더에 대해 리소스를 허용한다면 아무 출처에나 인증 정보를 줘버려서 보안에 문제가 생김
notion image
  • 따라서 서버가 다음과 같이 Header의 정보를 바꿔 주어야 함. 그래야 CORS 에러 발생안함

CORS 필요성

  • 웹은 모두에게나 열려 있기 때문에 F12를 눌러 개발자 도구로 들어가면 코드도 열람 가능하고 스크립트 또한도 조작이 가능함 ⇒ CSRF, XSS 같은 사용자 공격에 노출
    • 브라우저에 조작된 요청을 넣거나
    • 브라우저에 저장된 사용자 정보를 빼가는 공격이 있을 수 있음

CORS 우회하기

1. 프론트엔드에서 Proxy Server(서버의 출처로)를 활용

  • 브라우저는 axios 요청 시 프론트 엔드 출처끼리 리소스를 공유한다고 착각해 CORS를 따지지 않음
  • 하지만 background에서 webpack이 프론트엔드 서버와 백엔드 서버를 연결해 줌

webpack-dev-server

notion image

http-proxy-middleware (node server 사용시)

notion image

리액트 CRA

package.json에 아래 입력
notion image

Spring에서 CORS 허용가능하도록 설정하는법

CORS와 처리 방법에 대해
Baeldung — CORS with Spring
Fixing 401s with CORS Preflights and Spring Security

WebMvcConfigurer이용

class ServletConfig implements WebMvcConfigurer{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("*") // 모든 출처에 접근 허가를 내리면 보안에 문제 발생. // 필요한 부분에만 접근허가 해주기 .allowedMethods("GET"); // "*" 하면 모든 메서드 .allowedHeaders() .allowCredentials() } }
notion image

WebSecurityConfig

@EnableWebSecurity public class WebSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // ... http.cors(); return http.build(); } }

CorsFilter

  • 위의 http.cors() 를 활성화하면 CorsFilter가 생기게 되는데 해당 필터에서 WebConfig의 config를 불러와서 허용을 해줌. 만약에 CorsFilter를 통과 못하면 CORS 허용이 안됨. 에러 발생
  • 예를 들어 CorsFilter 앞의 Filter에서 response 만들어서 바로 내려줄 때, preflight 조차 CorsFilter를 통과하지 못하기에 CORS Error 가 발생하게 됨
 

@CrossOrigin 어노테이션 이용

  • Controller 클래스에 붙일 수도, 메서드에 붙일수도 있음
 

테스트 방법

curl -I -X OPTIONS \ -H "Origin: http://EXAMPLE.COM" \ -H 'Access-Control-Request-Method: GET' \ http://EXAMPLE.COM/SOMETHING 2>&1 | grep 'Access-Control-Allow-Origin'

Chrome 에서 CORS Disable/Enable

https://stackoverflow.com/questions/3102819/disable-same-origin-policy-in-chrome
open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --disable-site-isolation-trials --disable-web-security --user-data-dir="/tmp/chrome_dev_test"
Disable[Mac]
  • 위와 같이 실행하면 Chrome App 아이콘 하나 더 생기면서 걔만 CORS Disable된 버전으로 계속 키고 끌수 있음