티스토리 뷰

Spring

CORS 문제 해결하기

장진혁 2023. 3. 23. 18:14
프로젝트 시작 초기에 로그인, 회원가입을 구현 후
배포를 시작하고 처음으로 프론트분들과 접속을 시도했을때
CORS때문에 접속이 안되는 현상을 처음으로 경험했다.

우선 CSR, SSR이 뭔지 알아야 한다.
웹 애플리케이션을 렌더링하는 방식에 대한 차이가 있다.

CSR이란?
Client Side Rendering의 약자이다. 
CSR은 클라이언트 측에서 웹 페이지를 렌더링하는 방식입니다. 초기 페이지 로드 시 서버로부터 HTML, CSS, JavaScript 등의 리소스를 다운로드하고, 이후에 클라이언트 측에서 JavaScript를 사용하여 동적으로 웹 페이지를 렌더링합니다. 즉, 서버는 단순히 정적인 리소스를 제공하고, 클라이언트가 자바스크립트를 실행하여 동적으로 페이지를 구성합니다.

CSR의 장점은 초기 페이지 로드 속도가 빠르고, 웹 애플리케이션의 렌더링 속도가 빠르다는 것입니다. 또한, API를 사용하여 데이터를 가져오는 등의 비동기 작업을 쉽게 처리할 수 있습니다. 그러나 CSR의 단점은 초기 페이지 로드 시 빈 화면이 표시되며, 자바스크립트가 비활성화된 상태에서는 페이지가 제대로 렌더링되지 않는다는 것입니다.

SSR 란?
Server-Side Rendering의 약자이고
SSR은 서버 측에서 웹 페이지를 렌더링하는 방식입니다. 클라이언트 측에서 렌더링되는 것이 아니라, 초기 페이지 로드 시 서버에서 미리 렌더링된 HTML, CSS, JavaScript 등의 리소스를 클라이언트로 전송합니다. 클라이언트는 이후에 자바스크립트를 사용하여 동적인 요소를 렌더링합니다.

SSR의 장점은 초기 페이지 로드 시 사용자에게 빠른 첫 화면을 보여줄 수 있다는 것입니다. 또한, SEO(Search Engine Optimization)에 유리하며, 자바스크립트가 비활성화된 상태에서도 페이지가 정상적으로 렌더링된다는 것입니다. 그러나 SSR의 단점은 서버 부하가 높아질 수 있고, 클라이언트 측에서의 렌더링이 비교적 느리다는 것입니다.

 

내가 했던 프로젝트에서는 리엑트를 사용하는 프론트분들이랑 협업하면서
CSR방법의 렌더링 방식을 사용한다.

여기서 문제점은 Cross-Site HTTP Requests는 다른 곳에서 리소스를 불러오면서
Same Origin Policy를 적용 받기 때문에 요청을 해도 막혀서 리소스를 불러오지 못한다.

Same Origin Policy란?
웹 브라우저에서 실행되는 스크립트가 다른 출처(Origin)에서 로드된 문서나 리소스에 접근하는 것을 제한하는 보안 메커니즘입니다. 출처는 URL 스키마(http, https), 호스트명, 포트 번호로 구성됩니다.

Same Origin Policy의 규칙으로 인해서 접속이 불가하다.
1. 동일 출처일 경우 접근 가능 스크립트가 실행 중인 문서와 리소스의 출처가 같은 경우, 다른 출처의 문서나 리소스에 자유롭게 접근할 수 있습니다.
2. 프로토콜, 호스트, 포트 중 하나라도 다르면 접근 불가 스크립트가 실행 중인 문서와 리소스의 출처 중 프로토콜, 호스트, 포트 중 하나라도 다른 경우, 다른 출처의 문서나 리소스에 접근할 수 없습니다.
3. 동일 출처에서도 제한 가능 동일 출처에서도 Same Origin Policy를 적용할 수 있습니다. 이 경우는 보안 이슈가 있는 경우에 적용합니다.

 

이제 CORS가 뭔지 알아보자
CORS란?
CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 실행되는 스크립트가 다른 출처(origin)의 리소스에 접근할 수 있는 권한을 부여하는 웹 표준
CORS는 이러한 문제를 해결하기 위해 나온 웹 표준으로, 다른 출처의 리소스에 대한 접근 권한을 서버 측에서 설정해줌으로써 웹 브라우저에서 안전하게 다른 출처의 리소스를 사용할 수 있도록 합니다.
따라서 CORS를 구현하려면 서버 측에서 Access-Control-Allow-Origin 헤더를 설정해 주어야 하며, 클라이언트 측에서는 요청의 출처를 명시해 주어야 합니다. 만약 서버 측에서 출처를 지정해 주지 않으면, 웹 브라우저는 보안상의 이유로 해당 리소스에 접근을 차단합니다.
내가 프로젝트를 하면서 했던 스프링 시큐리티 CORS 설정
@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.csrf().disable();
        http.httpBasic().disable();
        http.formLogin().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.authorizeRequests()
                .antMatchers(HttpMethod.GET, "/api/board/detail/**").permitAll()
                .antMatchers(HttpMethod.GET, "/api/board/list").permitAll()
                .antMatchers("/api/user/signup", "/api/user/login", "/api/user/check", "/api/user/checknick").permitAll()
                .anyRequest().authenticated();

        http.cors();
        http.addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);

// 이 설정을 해주면, 우리가 설정한대로 CorsFilter가 Security의 filter에 추가되어
// 예비 요청에 대한 처리를 해주게 됩니다.
// cors 설정
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
		
        // 사전에 약속된 출처를 명시
        configuration.addAllowedOrigin("http://localhost:3000");
        
        // 특정 헤더를 클라이언트 측에서 사용할 수 있게 지정
        // 만약 지정하지 않는다면, Authorization 헤더 내의 토큰 값을 사용할 수 없음
        configuration.addExposedHeader(JwtUtil.AUTHORIZATION_HEADER);
        
        // 본 요청에 허용할 HTTP method(예비 요청에 대한 응답 헤더에 추가됨)
        configuration.addAllowedMethod("*");
        
        // 본 요청에 허용할 HTTP header(예비 요청에 대한 응답 헤더에 추가됨)
        configuration.addAllowedHeader("*");
        
        // 기본적으로 브라우저에서 인증 관련 정보들을 요청 헤더에 담지 않음
        // 이 설정을 통해서 브라우저에서 인증 관련 정보들을 요청 헤더에 담을 수 있도록 해줍니다.
        configuration.setAllowCredentials(true);
        
        // allowCredentials 를 true로 하였을 때,
        // allowedOrigin의 값이 * (즉, 모두 허용)이 설정될 수 없도록 검증합니다.
        configuration.validateAllowCredentials();
		
        // 어떤 경로에 이 설정을 적용할 지 명시합니다. (여기서는 전체 경로)
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
  1. **http.cors()**는 Spring Security에서 기본적으로 활성화된 CORS 구성을 사용하도록 지시합니다.
  2. @Bean은 스프링 프레임워크에서 Bean을 구성하는 데 사용되는 어노테이션입니다.
  3. CorsConfigurationSource는 CORS 구성을 구성하기 위한 인터페이스입니다. corsConfigurationSource() 메소드는 CorsConfiguration 객체를 생성하고 필요한 구성을 추가하여 CORS를 구성합니다.
  4. **configuration.addAllowedOrigin()**은 다른 도메인의 리소스 접근을 허용하는 도메인을 설정합니다. 여기서는 Amazon S3의 정적 웹 사이트 호스팅 URL을 추가했습니다.
  5. **configuration.addExposedHeader()**는 브라우저에서 액세스 가능한 헤더를 추가합니다. 여기서는 JWT (JSON Web Token)를 인증 헤더로 사용하기 위해 JwtUtil.AUTHORIZATION_HEADER를 추가합니다.
  6. **configuration.addAllowedMethod()**와 **configuration.addAllowedHeader()**는 각각 허용된 HTTP 메서드와 헤더를 설정합니다. *****를 사용하여 모든 메서드와 헤더를 허용합니다.
  7. **configuration.setAllowCredentials()**는 인증된 사용자의 자격 증명을 포함하여 요청과 응답에 쿠키를 허용할지 여부를 설정합니다.
  8. **configuration.validateAllowCredentials()**는 CORS 구성을 유효성 검사합니다.
  9. UrlBasedCorsConfigurationSource는 URL 경로별로 CORS 구성을 구성할 수 있도록 지원하는 인터페이스입니다

'Spring' 카테고리의 다른 글

resources/templates/login.html  (0) 2023.04.04
form-date, consumes와 produces의 차이점  (0) 2023.03.30
SQL, ORM, MVC  (0) 2023.03.20
Spring Security  (0) 2023.03.15
@Autowired 생략 가능?  (0) 2023.03.12
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함