[Spring] SOP & CORS

2024. 7. 6. 23:53BE/Spring

 

 

CORS(교차 출처 리소스 공유) | 토스페이먼츠 개발자센터

CORS를 번역하면 “교차 출처 리소스 공유”에요. ‘두 출처가 서로 다르다’는 뜻인데요. CORS를 설정한다는 건 ‘출처가 다른 서버 간의 리소스 공유’를 허용한다는 거죠.

docs.tosspayments.com

 


1. Origin이란?

 

  • Origin = Protocol + Host + Port

 


2. SOP란?

 

 

SOP(Same-Origin Policy, 동일 출처 정책)는 웹 보안의 중요한 개념 중 하나로, 특정 출처(origin)에서 로드된 문서나 스크립트가 다른 출처의 리소스와 상호작용하지 못하도록 제한하는 정책이다.

 

SOP는 웹 브라우저가 클라이언트 측에서 악의적인 스크립트가 다른 출처의 콘텐츠에 접근하지 못하도록 하기 위해 도입되었다.

 


가. 등장배경

 

SOP는 웹 애플리케이션의 보안성을 높이기 위해 도입되었다.

 

웹 브라우저는 다양한 출처에서 콘텐츠를 로드할 수 있는데, 악의적인 사이트가 사용자의 민감한 데이터를 탈취하거나 조작할 수 있는 위험이 존재한다.

 

이러한 보안 취약점을 방지하기 위해 SOP가 등장하게 되었다.

 


나. 문제점

 

문제점 설명
제한된 리소스 접근 서로 다른 출처에서 리소스를 공유해야 하는 웹 애플리케이션에서는 불편함을 초래할 수 있다.
개발 복잡성 증가 개발자는 SOP를 우회하기 위해 프록시 서버를 설정하거나 CORS(Cross-Origin Resource Sharing)를 사용해야 한다. 이는 개발 복잡성을 증가시키고, 추가적인 설정을 요구한다.
성능 이슈 SOP로 인해 추가적인 요청과 응답이 필요하게 되어 성능 저하가 발생할 수 있다. 특히, 프록시 서버를 사용하는 경우 네트워크 지연이 발생할 수 있다.
유연성 부족 SOP는 매우 엄격한 보안 정책으로, 유연성이 부족하다. 이는 사용자가 여러 출처에서 데이터를 동적으로 로드해야 하는 현대적인 웹 애플리케이션의 요구에 부합하지 않을 수 있다.

 

 

다른 출처 간의 안전한 리소스 공유를 위해서는 CORS와 같은 기술이 필요하다.

 


3. CORS란?

 

 

교차 출처 자원 공유(Cross-origin resource sharing)은 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다.

 

CORS를 설정한다는 건 ‘출처가 다른 서버 간의 리소스 공유’를 허용한다는 것이다.

 


가. CORS Error

 

cors-test.html:1 Access to XMLHttpRequest at 'http://localhost:8080/cors/test?id=1234&name=1234' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

웹 브라우저에서 어쩌다 볼 수 있는 CORS 경고 문구다.

 

이는 클라이언트 에러다.

 

웹 브라우저가 http://127.0.0.1:5500에서 http://localhost:8080로의 XMLHttpRequest를 Same-Origin Policy 때문에 차단했음을 나타낸다.

 

http://localhost:8080서버에게 요청한 리소스에 Access-Control-Allow-Origin 헤더가 없어서 브라우저가 요청을 차단했다.

 


나. Access-Control-Allow-Origin 응답 헤더

 

정상적인 CORS를 위해서는 Origin이 아닌 서버에서 Access-Control-Allow-Origin 헤더를 보내주어야 한다.

 

 


다. @CrossOrigin

 

@CrossOrigin()는 스프링 프레임워크에서 CORS를 설정하기 위해 사용되는 애너테이션이다.

 

이 애너테이션을 사용하면 특정 컨트롤러나 메서드에 대해 CORS 규칙을 적용할 수 있다.

 

애너테이션을 붙이는 위치에 따라 CORS 적용 범위가 다르다.

 

컨트롤러 클래스 위에 붙이면 해당 컨트롤러의 모든 메서드에 대해 CORS가 적용되고, 특정 메서드 위에 붙이면 그 메서드에만 CORS가 적용된다.

 

  • 컨트롤러 수준에서 CORS를 적용:
@CrossOrigin("*")
@RestController
@RequestMapping("/cors")
public class CorsRestController {
    Logger logger = LoggerFactory.getLogger(CorsRestController.class);
    // ...
}

 

  • 특정 메서드에만 CORS를 적용:
@CrossOrigin("*")
@GetMapping("test")
public ResponseEntity<String> test(String id, String name) throws Exception {
    return new ResponseEntity<String>("success.", HttpStatus.OK);
}
  • @CrossOrigin("*") : 모든 Origin에 대한 CORS 허용.
  • @CrossOrigin(origins = "http://domain1.com, http://domain2.com") : 복수의 Origin에 대한 CORS 허용.

 


3. CORS 시나리오

 

 

CORS와 Proxy를 활용하여 해결하기

CORS란 무엇이고 CORS의 시나리오는 어떤 것이 있으며 Proxy서버를 사용하여 해결하는 방법에 대해 설명한 글입니다.

velog.io

읽어보자.

 


가. CORS 시나리오

시나리오 설명
Preflight Request Preflight 요청은 CORS 요청이 실제 요청을 보내기 전에 서버의 허용 여부를 확인하기 위해 보내는 요청. 서버는 요청에 대해 허용 여부를 응답합니다.
Simple Request Simple 요청은 Preflight 요청이 필요 없는 간단한 CORS 요청. 주로 GET, POST, HEAD 메서드와 특정 헤더들로 제한됩니다.
Credentialed Request Credentialed 요청은 사용자 인증 정보(쿠키, 인증 헤더 등)를 포함하는 요청. 이러한 요청은 서버에서 Access-Control-Allow-Credentials 헤더를 통해 허용되어야 하며, 브라우저는 이를 준수해야 합니다.

 


나. Preflight Request

 

Preflight 요청은 브라우저가 본 요청을 보내기 전에 보내는 예비 요청(Preflight)을 보낸다.

 

Preflight 요청은 보통 Http method 중 OPTIONS를 사용한다.

 

OPTIONS 메서드는 HTTP 프로토콜에서 사용되는 메소드 중 하나로, 서버에게 특정 리소스에 대해 허용되는 HTTP 메서드와 기타 통신 옵션을 질의하는 데 사용된다.

 

이는 주로 CORS 요청에서 Preflight 요청을 위해 사용된다.

 

Preflight 요청을 보낼지는 브라우저가 스스로 판단한다.

 

  • Preflight 요청이 발생하는 조건:

 

조건 설명
HTTP 메서드 GET, POST, HEAD 이외의 메서드 (예: PUT, DELETE, OPTIONS 등)
사용자 정의 헤더 표준 헤더 외에 사용자 정의 헤더가 포함된 경우
Content-Type application/x-www-form-urlencoded, multipart/form-data, text/plain을 제외한 Content-Type (예: application/json)
Credentialed 요청 사용자 인증 정보(쿠키, 인증 헤더 등)를 포함하는 경우

 

하나라도 해당되면 preflight 요청이 발생한다.

 


다. Simple Request

 

Simple 요청은 주로 데이터 조회나 간단한 데이터 전송에 사용됩니다.

 

 

조건 설명
HTTP 메서드 GET, POST, HEAD
사용자 정의 헤더 없음 표준 헤더 외에 사용자 정의 헤더가 포함되지 않은 경우
Content-Type application/x-www-form-urlencoded, multipart/form-data, text/plain
Credentialed 요청 아님 사용자 인증 정보(쿠키, 인증 헤더 등)를 포함하지 않은 경우

하나라도 어기면 Preflight 요청이 발생합니다.

 


라. Credentialed Request

 

Credentialed Request는 사용자 인증 정보(쿠키, 인증 헤더 등)를 포함하는 요청을 말한다.

 

Credentialed Request는 서버에서 Access-Control-Allow-Credentials 헤더를 넣어줘야 한다.

 

Credentialed Request가 필요한 경우:

  • 쿠키를 포함한 요청을 보낼 때
  • Header에 Authorization 항목을 포함하여 요청을 보낼 때
 

🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏

악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이

inpa.tistory.com

 

Credentialed Request가 발생할 때 해야 할 일은 위에 블로그를 참고하든 검색하든 하자.

 


'BE > Spring' 카테고리의 다른 글

[Spring] SpringBoot  (0) 2024.07.06
[Spring] Rest API  (0) 2024.07.06
[Spring] 비동기 통신  (0) 2024.07.06
[Spring] MyBatis-Spring module  (0) 2024.07.06
[MyBatis] 동적 SQL  (0) 2024.07.06