기록

CORS 오류 해결하기: Spring Boot와 Swagger 본문

Web/Spring

CORS 오류 해결하기: Spring Boot와 Swagger

youngyin 2024. 11. 11. 04:11

시작하면서

웹 개발을 하다 보면 자주 겪게 되는 오류 중 하나가 CORS (Cross-Origin Resource Sharing) 관련 오류입니다. 이는 브라우저에서 다른 출처의 리소스를 요청할 때 발생하는 보안 문제로, 주로 API 서버와 클라이언트가 서로 다른 도메인에 있을 때 나타납니다. 오늘은 Spring Boot와 Swagger를 사용한 프로젝트에서 발생한 CORS 오류를 해결한 경험을 공유하며, CORS의 개념과 문제 해결 방법을 다뤄보겠습니다.

CORS란 무엇인가?

CORS는 Cross-Origin Resource Sharing의 약자로, "교차 출처 리소스 공유"를 의미합니다. 쉽게 말해, 한 웹 애플리케이션에서 실행되는 JavaScript 코드가 다른 도메인에 존재하는 리소스를 요청할 때 발생하는 보안 규칙입니다. 기본적으로, 웹 브라우저는 보안상의 이유로 다른 출처(origin)의 리소스를 요청하는 것을 차단합니다. 예를 들어, http://example.com에서 실행되는 웹 페이지가 http://api.example.com에서 제공하는 API를 호출하려고 하면, 브라우저는 이 요청을 차단할 수 있습니다.

이때, 서버에서 CORS 헤더를 통해 특정 도메인에 대해 요청을 허용하면, 브라우저가 해당 요청을 차단하지 않고 허용하게 됩니다.

CORS 오류의 원인

CORS 오류는 주로 클라이언트(브라우저)에서 API를 호출할 때 서버가 요청을 허용하지 않아서 발생합니다. 예를 들어, Spring Boot 서버가 localhost:8080에서 실행되고 있고, 클라이언트가 localhost:3000에서 실행되는 React 애플리케이션이라면, 서버는 기본적으로 다른 출처의 요청을 차단하게 됩니다. 이때 CORS 오류가 발생합니다.

CORS 오류 해결 과정

처음에는 다음과 같은 코드로 서버 URL을 동적으로 설정했습니다:

fun openApi(): OpenAPI {
    val profile: String = environment.getProperty("spring.profiles.active", "local")
    val host: String = InetAddress.getLocalHost().hostAddress
    val port: String = environment.getProperty("ec2.$profile.port", "8080")
    val version: String = environment.getProperty("apiProject.version", "V.0.0.0")

    val server = Server()
    server.url = "http://$host:$port"
    return OpenAPI().servers(listOf(server))
        .info(
            Info()
                .title("[$profile] Ilsang Api Document")
                .description("$profile 환경에서의 API 문서입니다.")
                .version("$version")
        )
        .security(
            listOf(
                SecurityRequirement()
                    .addList("authorization")
            )
        )
}

문제가 발생한 환경

Spring Boot와 Kotlin을 사용하여 API 서버를 개발하는 프로젝트에서 Swagger를 사용하고 있었습니다. Swagger는 API 문서화와 테스트를 돕는 도구로, 개발 중 자주 사용됩니다. 그러나 Swagger UI를 통해 API를 테스트하려고 할 때 CORS 오류가 발생했습니다. 문제의 원인은 EC2 환경에서 Swagger UI가 사용하는 서버 주소 설정이 실제 사용자들이 접근하는 주소와 일치하지 않았기 때문입니다.

문제 상황의 세부 원인 파악

이 프로젝트에서는 EC2 인스턴스에 Elastic IP (EIP)를 할당하여 사용자가 고정된 퍼블릭 IP를 통해 서버에 접근할 수 있도록 구성했습니다. 그러나 Spring Boot 설정에서 Swagger의 서버 주소를 가져오기 위해 InetAddress.getLocalHost().hostAddress를 사용했는데, 이 코드가 EC2의 Private IP를 반환했습니다. 그 결과, Swagger가 요청을 보낼 때 API 서버의 주소가 Private IP로 설정되었고, 사용자가 접속하는 EIP와는 서로 다른 출처(Cross-Origin)로 인식되어 CORS 오류가 발생했습니다.

문제 해결을 위한 수정

  1. 환경별 호스트 IP 정보 명시
ec2:
  prd:
    host: ${ELP_PRD}
    port: 8881
  dev:
    host: ${ELP_DEV}
    port: 8880
  local:
    host: localhost
    port: 8080
  1. .yml을 읽어와서 주소 정보를 설정하도록 수정

CORS 오류를 해결하기 위해, 서버의 주소 설정 방식을 변경했습니다. InetAddress.getLocalHost().hostAddress를 사용하던 부분을, 프로파일에 맞춰 서버 주소를 설정하는 방식으로 수정했습니다.

 

수정된 코드:

fun openApi(): OpenAPI {
    val profile: String = environment.getProperty("spring.profiles.active", "local")
    val host: String = environment.getProperty("ec2.$profile.host", "localhost")
    val port: String = environment.getProperty("ec2.$profile.port", "8080")
    val version: String = environment.getProperty("apiProject.version", "V.0.0.0")

    val server = Server()
    server.url = "http://$host:$port"
    return OpenAPI().servers(listOf(server))
        .info(
            Info()
                .title("[$profile] Ilsang Api Document")
                .description("$profile 환경에서의 API 문서입니다.")
                .version("$version")
        )
        .security(
            listOf(
                SecurityRequirement()
                    .addList("authorization")
            )
        )
}

 

 이렇게 함으로써 Swagger UI가  고정된 서버 URL을 사용하게 되어 CORS 문제가 해결되었습니다.

(다른방법) CORS 오류 해결 방법

CORS 오류를 해결하기 위한 몇 가지 방법은 다음과 같습니다:

  1. 서버에서 CORS 정책 설정:
    Spring Boot에서는 @CrossOrigin 어노테이션을 사용하거나 CorsRegistry를 통해 CORS 정책을 설정할 수 있습니다. 이를 통해 특정 도메인만 허용하거나 모든 도메인에서의 요청을 허용할 수 있습니다.
    @Configuration
    class WebConfig : WebMvcConfigurer {
        override fun addCorsMappings(registry: CorsRegistry) {
            registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000") // 허용할 클라이언트 주소
                .allowedMethods("GET", "POST", "PUT", "DELETE")
        }
    }
  2. 예시 코드:
  3. 서버 URL을 환경에 맞게 동적으로 설정:
    위에서 설명한 것처럼, 서버의 호스트와 포트 정보를 환경 설정에 맞춰 동적으로 지정하면 CORS 오류를 피할 수 있습니다. 개발 환경, 테스트 환경, 프로덕션 환경에 따라 서버 주소가 달라지므로, 이를 동적으로 설정하는 방식이 필요합니다.
  4. 프록시 서버 사용:
    개발 중이라면 프록시 서버를 사용하여 CORS 문제를 우회할 수 있습니다. 예를 들어, create-react-app에서는 proxy 설정을 통해 CORS 문제를 해결할 수 있습니다.

마무리하면서

CORS 오류는 클라이언트와 서버가 서로 다른 출처에서 리소스를 요청할 때 발생하는 보안 관련 문제입니다. Spring Boot와 Swagger를 사용하면서 경험한 CORS 오류를 해결하는 과정에서, CORS가 발생하는 원인과 이를 해결하는 방법에 대해 더 깊이 이해할 수 있었습니다.

Comments