CORS
CORS (Cross-Origin Resource Sharing)는 'Cross-Origin Resource Sharing'의 약어로, 웹 보안 메커니즘 중 하나입니다. 이 메커니즘은 웹 브라우저에서 실행되는 웹 페이지가 다른 웹사이트(출처)에서 데이터를 요청할 때 발생할 수 있는 보안 정책 중 하나입니다. 서로 다른 출처(origin) 간에 데이터 공유하려하면 이를 제한하는 보안 메커니즘(SOP, Same-Origin Policy)에 의해 CORS 오류가 발생하게 됩니다. 이러한 CORS 에러를 해결하기 위해선 CORS를 설정하여, 출처가 다른 서버 간의 리소스 공유를 허용해주어야합니다.
출처(Origin): Protocol + Hostname(Domain) + Port
· 도메인(Hostname): dutmdcjf.com
· 출처(Origin): https://dutmdcjf.com:8080
SOP (Same-Origin Policy):
Same-Origin Policy는 브라우저에서 실행되는 웹 페이지가 다른 출처(origin)으로부터 가져온 리소스(데이터, 스크립트, 이미지 등)에 접근을 제한하는 보안 메커니즘입니다. 동일한 도메인에서 로드된 페이지는 다른 도메인으로부터 리소스를 요청하거나 접근할 수 있지만, 다른 도메인으로부터 로드된 페이지는 제한됩니다. 이를 통해 사용자의 보안과 웹 애플리케이션을 보호합니다.
CORS (Cross-Origin Resource Sharing):
CORS는 Same-Origin Policy의 예외로, 다른 출처(Origin) 간에 데이터 공유를 가능하게 합니다. 웹 애플리케이션은 다른 출처의 리소스에 접근하기 위해 CORS 정책을 사용하여 브라우저에 요청을 허용하도록 설정할 수 있습니다. 이를 통해 서로 다른 출처 간에 데이터 교환을 효과적으로 관리할 수 있습니다.
Same-Origin Policy 따르는 이유
개인 정보 노출:
Same-Origin Policy를 따르지 않으면 웹 페이지가 다른 도메인의 리소스에 자유롭게 접근할 수 있으므로, 사용자의 개인 정보가 노출될 수 있습니다. 예를 들어, 사용자가 은행 웹사이트에 로그인한 상태에서 다른 웹사이트에 접속하면, 악의적인 웹사이트는 사용자의 은행 계좌 정보에 접근할 수 있습니다.
CSRF (Cross-Site Request Forgery) 공격:
Same-Origin Policy를 따르지 않으면 CSRF 공격에 취약해집니다. 이 공격은 사용자가 자신의 의지와 무관하게 다른 웹사이트에서 악의적인 요청을 보내도록 유도하는 것을 의미합니다. 예를 들어, 사용자가 은행 웹사이트에 로그인한 상태에서 악의적인 웹사이트를 방문하면, 악의적인 웹사이트가 사용자의 은행 계좌에서 돈을 이체하는 등의 요청을 보낼 수 있습니다.
크로스 사이트 스크립팅 (XSS) 공격:
Same-Origin Policy를 따르지 않으면 XSS 공격에 취약해질 수 있습니다. XSS 공격은 악의적인 스크립트가 웹 페이지에 삽입되어 사용자의 브라우저에서 실행되는 공격입니다. 다른 도메인에서 로드된 스크립트가 현재 페이지와 상호작용하면 보안 문제가 발생할 수 있습니다.
쿠키 및 세션 토큰 노출:
Same-Origin Policy를 따르지 않으면 쿠키와 세션 토큰이 다른 도메인에 노출될 수 있습니다. 이로 인해 세션 해킹과 같은 공격이 발생할 수 있으며, 사용자의 계정이 해킹될 위험이 있습니다.
CORS 동작 순서 및 흐름
- 클라이언트 요청:
브라우저(클라이언트)에서 다른 출처(origin)로 HTTP 요청을 보냅니다. 이때 요청에서 중요한 헤더 두 가지가 있습니다.
Origin 헤더: 클라이언트의 출처(origin)를 나타내며, 어떤 도메인에서 요청이 시작되었는지를 나타냅니다.
Access-Control-Request-Method 헤더: 실제 HTTP 요청에서 사용될 메서드(GET, POST 등)를 나타냅니다. 브라우저는 사전 요청(preflight request)에서 이 헤더를 서버에 전달하여 지원하는 메서드를 확인합니다. - (옵션) Preflight 요청:
만약 요청이 'Simple Request'가 아닌 경우, 브라우저는 먼저 `OPTIONS 메서드`를 사용하여 Preflight 요청을 보냅니다. 이 요청은 브라우저에서 요청을 실제 요청을 보내기 전에 서버에서 허용되는지 확인하는 예비 요청 역할을 합니다.
※ Simple Request: 브라우저에서 Proflight없이 바로 서버에 보내는 요청입니다. 이 요청은 CORS의 조건을 모두 충족하는 경우에 해당합니다.- 요청이 `GET`, `POST`, `HEAD` 중 하나의 HTTP 메서드를 사용해야합니다.
- 요청에 사용자 지정 헤더가 없거나, 일부 표준 HTTP 헤더만 사용해야합니다. 예를 들어 클라이언트가 임의로 추가한 헤더인 `Authorization`헤더를 설정한 경우 부합하지 않습니다.
- Content-Type 헤더: 요청이 `POST 메서드`를 사용할 때 `Content-Type`헤더의 값은 다음 중 하나여야 합니다.
`application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain` - 요청이 인증 정보(쿠키, HTTP 인증 등)를 포함하지 않아야합니다. 이러한 정보가 요청에 포함되어 있는 경우 Preflight 요청이 필요합니다.
- 동기적인 요청인 경우입니다. 브라우저에서 CORS 요청은 기본적으로 비동기적으로 처리됩니다. 동기적인 요청은 `XMLHttpRequest`의 `withCredentials` 속성을 `true`로 설정한 경우이며, 이 경우 Preflight 요청이 필요합니다.
- 서버의 응답:
서버는 클라이언트의 요청을 받고, 이 요청이 허용되는지 확인합니다. 서버는 응답 헤더에 CORS 관련 정보를 포함하여 클라이언트에게 알립니다. 이 헤더에는 다음과 같은 내용이 포함됩니다:
Access-Control-Allow-Origin: 요청을 보낸 도메인 또는 "*" (모든 도메인)
Access-Control-Allow-Methods: 허용된 HTTP 메서드 (GET, POST 등)
Access-Control-Allow-Headers: 허용된 HTTP 헤더
Access-Control-Allow-Credentials: 인증 정보를 포함하는 요청을 허용할지 여부 (true 또는 false)
Access-Control-Expose-Headers: 브라우저에서 접근 가능한 헤더 목록 - 브라우저의 확인:
브라우저는 서버의 응답을 확인하고, 허용된 경우 요청을 처리합니다.
만약 서버의 응답이 CORS 정책을 위반한다면, 브라우저는 JavaScript에서 해당 요청을 차단하고, 오류를 발생시킵니다.
CORS 문제 해결하는 방법
1. 서버 측에서 CORS 헤더 설정:
서버에서 CORS 헤더를 설정하여 어떤 origin에서의 요청을 허용할지 설정해주면 됩니다.
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 적용 경로
.allowedOrigins("http://localhost:8080") // 허용할 Origin 설정
.allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드 설정
.allowedHeaders("*"); // 모든 헤더 허용
.allowCredentials(true); // 인증 정보(coockie, HTTP 인증 헤더 등) 전송 여부
}
}
@RestController
@CrossOrigin(origins = "http://localhost:8080") // 클래스 단위에서 CORS 설정
public class MyController {
@GetMapping("/public")
public ResponseEntity<String> getPublicData() {
return ResponseEntity.ok("Public data");
}
@GetMapping("/restricted")
@CrossOrigin(origins = "http://trusted-client.com") // 메서드 단위에서 CORS 설정 (클래스 설정을 덮어씁니다.)
public ResponseEntity<String> getRestrictedData() {
return ResponseEntity.ok("Restricted data");
}
}
2. 클라이언트 측에서 요청 수정:
서버에서 CORS 설정을 하고 `allowCredentials`를 `true`로 설정한 경우, 클라이언트 측에서도 `withCredentials` 옵션을 설정해주어야 합니다. 위 주석으로 설명했듯이`allowCredentials`를 `true`로 설정한 서버는 인증 정보(cookies, HTTP 인증 헤더 등)를 요청과 함께 허용하겠다고 선언한 것입니다. 따라서 클라이언트는 이를 활성화하기 위해 요청을 보낼 때 `withCredentials` 옵션을 `true`로 설정해야 합니다.
axios.get(URL, {
withCredentials: true // 인증 정보를 요청과 함께 보냄
})
이렇게 `withCredentials: true`를 설정하면 클라이언트는 요청과 함께 인증 정보를 보내고, 서버에서 CORS 설정에 `allowCredentials: true`가 있다면 요청을 허용합니다.
3. 프록시 서버 사용:
클라이언트와 서버 사이에 프록시 서버를 두어 클라이언트에서 프록시 서버로 요청을 보내고, 프록시 서버에서 실제 서버로 요청을 전달하여, CORS 문제를 해결할 수 있습니다.
4. 서버 측에서 미들웨어 또는 라이브러리 사용:
Spring Boot에서는 `Spring Security`를 사용하여 정교한 보안 설정을 할 수 있고, 이를 통해CORS와 관련된 인증 및 권한 설정을 제어할 수 있습니다.
5. 브러우저 확장 프로그램 설치
브라우저 확장 프로그램을 이용하여 코드를 따로 바꾸지 않고도 개발자 환경에서 CORS 문제를 쉽고 빠르게 테스트 해볼 수 있습니다.
- 확장 프로그램: CORS Unblock
'Web' 카테고리의 다른 글
OpenSSL을 통해 RSA 공개키, 개인키 생성하기 (0) | 2024.03.12 |
---|---|
웹 보안을 위한 XSS, CSRF 방어 (1) | 2023.11.13 |
웹 데이터 저장: 로컬 스토리지, 세션 스토리지, 쿠키 (0) | 2023.09.18 |
Jar와 War의 차이(spring initializr packaging) (0) | 2023.09.01 |
Servlet에 대해 알아보자!! 동작 원리 파악하기 (0) | 2023.08.31 |