같은 Origin에만 요청을 보낼 수 있게 제한하는 보안 정책
서버가 아닌 브라우저에 비교 로직 구현
출처(Origin) : Protocol + Host + Port
기준 : https://www.google.com
같은 출처 : o
다른 출처 : x
https://www.google.com/user o
https://www.google.com/user?q=123 o
http://www.google.com x (protocol)
https://www.naver.com x (Host)
XSS(Cross-Site Scripting) / CSRF(Cross-Site Request Forgery) 공격 방지
악성코드를 웹사이트에 심어 사용자의 정보를 빼내는 공격 방식
로그인 상태에서 해커의 웹페이지 방문시 사용자의 로그인 데이터 악용
HTTP통신을 할 때, 다른 출처의 자원을 허용
-> Access-Contorl-Allow-Orgin 헤더의 값 세팅을 통해 브라우저에게 허용된 출처임을 알려준다
CORS를 설정하지 않으면 다른 origin의 자원 공유시 아래와 같은 오류 발생
Filter 인터페이스를 implements하여 CorsFilter 생성
필터의 로직을 수행하는 doFilter를 커스텀
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"); // Origin(URL)
response.setHeader("Access-Control-Allow-Credentials", "true");
//클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 true. true를 응답받은 클라이언트는 실제 요청 시 서버에서 정의된 규격의 인증값이 담긴 쿠키를 같이 보내야 한다.
response.setHeader("Access-Control-Allow-Methods","*"); // GET, POST, ...
response.setHeader("Access-Control-Max-Age", "3600"); // preflight 결과를 원하는 시간만큼 저장
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization");
// 실제 요청시 사용할 수 있는 헤더
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
}
}
preflight : cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 본 요청 이전 실제 요청이 안전한지에 대한 preflight request 과정을 수행
참고: https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
@RestController
@RequestMapping(value = "/api/threats", produces = "application/json")
@CrossOrigin(origins = "http://front-server.com") // 컨트롤러에서 설정
public class ThreatController {
private final ThreatService threatService;
public ThreatController(ThreatService threatService) {
this.threatService = threatService;
}
@GetMapping
@CrossOrigin(origins = "http://front-server.com") // 메서드에서 설정
public ResponseEntity<ThreatLogCountResponse> getAllThreatLogs() {
return ResponseEntity.ok(threatService.getAllThreatLogCount());
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // CORS를 적용할 URL 패턴 정의
.allowedOrigins("http://localhost:8080");
// 자원 공유를 허용할 Origin 설정
}
}