CORS : Non-Simple Request / Simple Request

2023. 6. 20. 15:35Spring Security

📌 CORS: Simple Request와 Non-Simple Request의 차이점

1. CORS란? 🛡️

CORS(Cross-Origin Resource Sharing)는 웹 애플리케이션이 다른 출처(origin)에서 리소스를 요청할 수 있도록 허용하는 보안 메커니즘입니다. 보안 정책의 일환으로, 브라우저는 동일 출처 정책(Same-Origin Policy)을 디폴트로 적용하지만, 특정 조건을 충족하면 교차 출처 요청을 허용할 수 있습니다.

CORS는 서버가 특정 출처에서 오는 요청을 허용할지 결정하는데, 이때 Simple Request(단순 요청)Non-Simple Request(비단순 요청)을 구분하여 다르게 처리합니다. 🚀

 

2. Simple Request(단순 요청) 🟢

✅ Simple Request란?

Simple Request는 브라우저가 사전 요청(Preflight 요청, OPTIONS 요청)을 수행하지 않고 직접 서버에 요청을 보낼 수 있는 요청을 의미합니다.

이 요청이 단순한지 판단하는 기준은 다음과 같습니다:

📌 Simple Request의 조건

  1. HTTP 메소드 제한
    • 요청의 메소드는 GET, POST, HEAD 중 하나여야 합니다.
  2. Content-Type 제한
    • 요청의 Content-Type이 다음 값 중 하나여야 합니다:
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • 즉, application/json 같은 Content-Type은 단순 요청이 아닙니다. ❌
  3. 사용자 정의 헤더 없음
    • Authorization, X-Custom-Header브라우저가 기본적으로 제공하지 않는 사용자 정의 헤더를 포함하면 안 됩니다.
    • 기본적인 Accept, Content-Type, User-Agent 등만 허용됩니다.

✅ Simple Request의 예시

1️⃣ GET 요청 (단순 요청 ✅)

GET /api/data HTTP/1.1
Host: server.com
Origin: https://client.com

2️⃣ POST 요청 (Content-Type이 application/x-www-form-urlencoded인 경우 ✅)

POST /api/data HTTP/1.1
Host: server.com
Origin: https://client.com
Content-Type: application/x-www-form-urlencoded

key1=value1&key2=value2

이러한 요청은 브라우저가 사전 요청(Preflight Request)을 보내지 않고 바로 서버에 요청을 보냅니다.

✅ Simple Request의 서버 응답

서버는 단순 요청을 허용할 경우, 다음과 같은 응답을 반환해야 합니다:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://client.com
Content-Type: application/json

{"message": "Hello, World!"}

 

3. Non-Simple Request(비단순 요청) 🔴

❌ Non-Simple Request란?

Non-Simple Request(비단순 요청)는 브라우저가 보안상의 이유로 Preflight 요청(OPTIONS 요청)을 먼저 보내서 서버의 허용 여부를 확인해야 하는 요청입니다. 즉, 서버가 해당 요청을 수락할지 사전에 확인하는 과정이 필요합니다. ⚠️

📌 Non-Simple Request의 조건

아래 세 가지 조건 중 하나라도 위반하면 비단순 요청이 됩니다:

  1. 허용되지 않은 HTTP 메소드 사용
    • GET, POST, HEAD 이외의 HTTP 메소드를 사용할 경우
    • 예: PUT, DELETE, PATCH, OPTIONS
  2. 허용되지 않은 Content-Type 사용
    • application/json 같은 Content-Type을 사용할 경우
  3. 사용자 정의 헤더 포함
    • X-Custom-Header, Authorization, X-Requested-With 등의 헤더가 포함될 경우

❌ Non-Simple Request의 예시

1️⃣ PUT 요청 (비단순 요청 🚨)

PUT /api/resource HTTP/1.1
Host: server.com
Origin: https://client.com
Content-Type: application/json

{"key": "value"}

2️⃣ 사용자 정의 헤더 포함 요청 (비단순 요청 🚨)

POST /api/resource HTTP/1.1
Host: server.com
Origin: https://client.com
Content-Type: application/x-www-form-urlencoded
X-Custom-Header: CustomValue

key1=value1&key2=value2

🔄 Preflight 요청(OPTIONS 요청)이 필요한 이유

위와 같은 비단순 요청이 발생하면, 브라우저는 먼저 Preflight 요청을 보내서 서버가 해당 요청을 허용하는지 확인합니다.

📌 Preflight 요청 예시 (OPTIONS 메소드 사용)

OPTIONS /api/resource HTTP/1.1
Host: server.com
Origin: https://client.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

✅ 서버의 Preflight 응답

서버는 다음과 같은 응답을 반환하여 요청을 허용할 수 있습니다:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://client.com
Access-Control-Allow-Methods: PUT, POST, DELETE
Access-Control-Allow-Headers: Content-Type, X-Custom-Header

이 응답을 받은 후, 브라우저는 실제 요청을 서버에 전송합니다. 🎯

 

4. CORS 정책 설정하기 🛠️

CORS를 올바르게 설정하지 않으면 브라우저에서 요청이 차단될 수 있습니다. 따라서, 서버에서 올바르게 CORS 정책을 설정해야 합니다.

✅ Spring Boot에서 CORS 설정 (Java)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("https://client.com")
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        .allowedHeaders("Content-Type", "Authorization");
            }
        };
    }
}

✅ Express.js에서 CORS 설정 (Node.js)

const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors({
    origin: 'https://client.com',
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization']
}));

 

5. 결론 🎯

Simple Request는 추가적인 보안 검증 없이 바로 요청할 수 있는 경우이며, Non-Simple Request는 보안 검증을 위해 Preflight 요청이 필요한 경우입니다.

 

📌 올바른 CORS 정책을 설정하면, 브라우저에서의 요청 차단을 방지하고 보안성을 유지하면서도 원활한 API 통신을 가능하게 할 수 있습니다! 🚀

'Spring Security' 카테고리의 다른 글

ch03 Managing users  (0) 2024.02.25
Ch02 Hello Spring Security  (0) 2024.02.25
Options  (0) 2023.06.10
CSRF  (0) 2023.06.08
Jason Web Token  (0) 2023.04.17