2024. 7. 6. 23:53ㆍBE/Spring
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 시나리오
시나리오 | 설명 |
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 항목을 포함하여 요청을 보낼 때
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 |