CORS(Cross-Origin Resource Sharing)
교차 출처 리소스 공유
브라우저가 자신의 출처가 아닌 다른 어떤 출처(도메인, 스킴 혹은 포트)로부터 자원을 로딩하는 것을 허용하도록 서버가 허가 해주는 HTTP 헤더 기반 메커니즘
또한 CORS는 교차 출처 리소스를 호스팅하는 서버가 실제 요청을 허가할 것인지 확인하기 위해 브라우저가 보내는 "사전 요청(프리플라이트, Preflight)" 메커니즘에 의존
이 사전 요청에서 브라우저는 실제 요청에서 사용할 HTTP 메서드와 헤더들에 대한 정보가 표시된 헤더에 담아 보냅니다.
https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CORS
브라우저 보안 규칙
웹페이지가 로드된 출처(origin)가 아닌 다른 출처의 서버에 요청을 보내려면 서버가 명시적으로 허용해야 한다.
이 출처에서 오는 요청은 허용함이라고 서버가 말해줘야함
CORS는 서버에서 설정
CORS는 브라우저 보안 정책이며, 서로 다른 origin 간 요청을 허용할지 여부를 서버가 명시적으로 선언하도록 강제하는 메커니즘이다.
// CORS 상세 설정 빈
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// Vue 프로젝트가 실행되는 주소를 넣으세요 (기본적으로 5173 또는 3000)
configuration.addAllowedOrigin("http://localhost:5173");
configuration.addAllowedMethod("*"); // GET, POST, PUT, DELETE 모두 허용
configuration.addAllowedHeader("*"); // 모든 헤더 허용
configuration.setAllowCredentials(true); // 쿠키나 인증 정보 허용
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration); // 모든 경로에 대해 적용
return source;
}
이게 없으면 생기는 문제
악성 사이트가 로그인된 사용자의 쿠키를 이용해 은행 API, 내부 ERP API 호출 가능
-> CSRF + 정보 탈취 위험
그래서 브라우저가 기본 차단하고 서버가 허용한 경우만 열어주는 구조
credentials 를 쓰면 왜 addAllowedOrigin 말고 addAllowedOriginPattern 을 써야하는지
credentials(true) + CORS 스펙 제약 + Spring 구현 차이 때문에
configuration.setAllowCredentials(true);
쿠키, 세션, Authorization 헤더 포함해서 요청 보내도 됨
credentials 쓰면 반드시 특정 Origin 지정해줘야함 * 전체 허용 안됨
addAllowedOrigin(*) 이런 거 안된다느 거
-> 전 세계 모든 사이트가 사용자 쿠키 들고 요청 가능
Access-Control-Allow-Origin : *
Access-Control-allow-Credentials : true
이 조합은 절대 불가
addAllowedOrigin(*) 이런 거 안된다느 거
-> 전 세계 모든 사이트가 사용자 쿠키 들고 요청 가능
모든 출처에서 쿠키를 보내는 걸 허용하면 보안 붕괴
그래서 credentials=true -> 반드시 특정 origin 명시
요청 Origin 헤더 값 == 설정된 문자열
완전히 같아야 허용
조금이라도 다르면 차단
http://localhost:5173 이렇게 들어온 거 아니면 다 차단됨
가운데가 127.0.0.1 이거나 5173 뒤에 /붙어서 들어온다거나 https 가 들어온다거나 등등 문자 하나라도 다르면 실패
addAllowedOrigin()은 * 불가
addAllowedOrigin("http://localhost:*"); // 불가능
addAllowedOriginPattern()은 Origin을 규칙(패턴)으로 매칭한다.
addAllowedOriginPattern("http://localhost:*");
가능 모든 포트로 들어오는 거 가능
# application-dev.yml
cors:
allowed-origins: http://localhost:*
# application-prod.yml
cors:
allowed-origins: https://www.myapp.com
Cross-Site Request Forgery
사용자가 로그인된 상태를 악용해 의도하지 않은 요청을 보내는 공격
브라우저가 자동으로 쿠키를 실어 보내는 특성을 이용한 공격
<form action="https://bank.com/transfer" method="POST">
POST/PUT/DELETE 요청 시 CSRF 토큰 없으면 차단
.csrf(csrf -> csrf
.ignoringRequestMatchers("/api/**")
)
이 경로들은 CSRF 검사 안 하겠다.
CSRF는 브라우저 + 쿠키 기반 인증에서만 의미 있음
만약 JWT, Authorization 헤더, 모바일 앱/SPA
-> CSRF 의미 거의 없음