한국어

CORS(교차 출처 리소스 공유)의 비밀을 파헤치고 웹 애플리케이션에서 안전하게 교차 도메인 요청을 활성화하는 방법을 배워보세요. 이 종합 가이드는 기본부터 고급 설정까지 모든 것을 다루어, 다른 출처 간의 원활하고 안전한 통신을 보장합니다.

CORS 완전 정복: 교차 출처 리소스 공유에 대한 종합 가이드

오늘날 서로 연결된 웹 환경에서 애플리케이션은 종종 다른 출처의 리소스에 접근해야 합니다. 바로 이럴 때 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)가 사용됩니다. CORS는 웹 브라우저가 한 출처(도메인, 프로토콜, 포트)에서 다른 출처로의 요청을 처리하는 방식을 제어하는 중요한 보안 메커니즘입니다. 안전하고 기능적인 웹 애플리케이션을 구축하기 위해 모든 웹 개발자는 CORS를 필수적으로 이해해야 합니다.

동일 출처 정책(Same-Origin Policy)이란 무엇인가?

CORS를 살펴보기 전에, 동일 출처 정책(Same-Origin Policy, SOP)을 이해하는 것이 중요합니다. SOP는 웹 브라우저에 구현된 기본적인 보안 메커니즘입니다. 이 정책의 목적은 한 웹사이트의 악성 스크립트가 다른 웹사이트의 민감한 데이터에 접근하는 것을 방지하는 것입니다. 출처는 프로토콜(예: HTTP 또는 HTTPS), 도메인(예: example.com), 포트 번호(예: 80 또는 443)의 조합으로 정의됩니다. 두 URL이 동일한 프로토콜, 도메인, 포트를 공유하면 동일한 출처를 가진 것으로 간주됩니다.

예시:

SOP는 CORS와 같은 특정 조치가 허용하지 않는 한, 스크립트가 다른 출처의 리소스에 접근하는 것을 제한합니다.

CORS가 필요한 이유는 무엇인가?

동일 출처 정책은 보안에 필수적이지만, 때로는 제약이 될 수 있습니다. 많은 현대 웹 애플리케이션은 API나 콘텐츠 전송 네트워크(CDN)와 같은 다른 서버에서 데이터를 가져오는 것에 의존합니다. CORS는 보안을 유지하면서 SOP를 완화하고 합법적인 교차 출처 요청을 허용하는 통제된 방법을 제공합니다.

http://example.com에 호스팅된 웹 애플리케이션이 http://api.example.net에 호스팅된 API 서버에서 데이터를 가져와야 하는 시나리오를 생각해 보십시오. CORS가 없다면 브라우저는 SOP 때문에 이 요청을 차단할 것입니다. CORS는 API 서버가 어떤 출처가 자신의 리소스에 접근할 수 있는지 명시적으로 지정할 수 있게 하여 웹 애플리케이션이 올바르게 작동하도록 합니다.

CORS의 작동 방식: 기본

CORS는 클라이언트(브라우저)와 서버 간에 교환되는 일련의 HTTP 헤더를 통해 작동합니다. 서버는 이 헤더를 사용하여 요청된 리소스에 접근이 허용되는지 여부를 브라우저에 알립니다. 관련된 핵심 HTTP 헤더는 Access-Control-Allow-Origin입니다.

시나리오 1: 단순 요청(Simple Request)

"단순 요청"은 특정 기준(예: Content-Type 헤더가 application/x-www-form-urlencoded, multipart/form-data, 또는 text/plain 중 하나)을 충족하는 GET, HEAD, POST 요청입니다. 이 경우, 브라우저는 요청을 서버로 직접 보내고, 서버는 Access-Control-Allow-Origin 헤더와 함께 응답합니다.

클라이언트 요청 (http://example.com에서):

GET /data HTTP/1.1
Host: api.example.net
Origin: http://example.com

서버 응답 (http://api.example.net에서):

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

{
  "data": "서버에서 온 데이터"
}

이 예에서 서버는 Access-Control-Allow-Origin: http://example.com으로 응답하여 http://example.com에서의 요청이 허용됨을 나타냅니다. 만약 요청의 출처가 Access-Control-Allow-Origin 헤더의 값과 일치하지 않거나 헤더가 없는 경우, 브라우저는 응답을 차단하고 클라이언트 측 스크립트가 데이터에 접근하는 것을 막습니다.

시나리오 2: 프리플라이트 요청(Preflight Request) (복잡한 요청의 경우)

PUT, DELETE와 같은 HTTP 메서드를 사용하거나 사용자 지정 헤더가 있는 더 복잡한 요청의 경우, 브라우저는 HTTP OPTIONS 메서드를 사용하여 "프리플라이트" 요청을 수행합니다. 이 프리플라이트 요청은 실제 요청을 보내기 전에 서버에 허가를 요청합니다. 서버는 허용되는 메서드, 헤더, 출처를 지정하는 헤더로 응답합니다.

클라이언트 프리플라이트 요청 (http://example.com에서):

OPTIONS /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

서버 응답 (http://api.example.net에서):

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 3600

헤더 설명:

서버의 프리플라이트 응답이 요청이 허용됨을 나타내면, 브라우저는 실제 요청을 진행합니다. 그렇지 않으면 브라우저는 요청을 차단합니다.

클라이언트 실제 요청 (http://example.com에서):

PUT /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
X-Custom-Header: some-value
Content-Type: application/json

{
  "data": "업데이트할 데이터"
}

서버 응답 (http://api.example.net에서):

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

{
  "status": "데이터가 성공적으로 업데이트되었습니다"
}

주요 CORS 헤더

다음은 이해해야 할 주요 CORS 헤더에 대한 설명입니다:

다양한 서버 측 언어에서의 CORS

CORS를 구현하는 것은 일반적으로 서버 측 애플리케이션이 적절한 CORS 헤더를 보내도록 구성하는 것을 포함합니다. 다음은 다양한 언어 및 프레임워크에서 이를 수행하는 방법에 대한 예입니다:

Node.js와 Express

cors 미들웨어 패키지를 사용할 수 있습니다:

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

const app = express();

// 모든 출처에 대해 CORS 허용 (프로덕션 환경에서는 주의해서 사용)
app.use(cors());

// 또는 특정 출처에 대해 CORS 설정
// app.use(cors({
//   origin: 'http://example.com'
// }));

app.get('/data', (req, res) => {
  res.json({ message: '모든 출처에 대해 CORS가 활성화되었습니다!' });
});

app.listen(3000, () => {
  console.log('서버가 3000번 포트에서 실행 중입니다');
});

Python과 Flask

Flask-CORS 확장을 사용할 수 있습니다:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

# 또는 특정 출처에 대해 CORS 설정
# CORS(app, resources={r"/api/*": {"origins": "http://example.com"}})

@app.route("/data")
def hello():
    return {"message": "모든 출처에 대해 CORS가 활성화되었습니다!"}

if __name__ == '__main__':
    app.run(debug=True)

Java와 Spring Boot

애노테이션이나 구성 클래스를 사용하여 Spring Boot 애플리케이션에서 CORS를 구성할 수 있습니다:

애노테이션 사용:

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(origins = "http://example.com") // http://example.com에서의 요청 허용
public class DataController {

    @GetMapping("/data")
    public String getData() {
        return "http://example.com에 대해 CORS가 활성화되었습니다!";
    }
}

구성 사용:

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 CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/data")
                .allowedOrigins("http://example.com") // http://example.com에서의 요청 허용
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*");
    }
}

PHP

 "http://example.com에 대해 CORS가 활성화되었습니다!");
echo json_encode($data);
?>

CORS와 보안 고려 사항

CORS가 교차 출처 요청을 가능하게 하지만, 안전하게 구현하는 것이 중요합니다. 다음은 몇 가지 중요한 고려 사항입니다:

CORS 문제 해결

CORS 문제는 디버깅하기 까다로울 수 있습니다. 다음은 몇 가지 일반적인 문제와 해결 방법입니다:

디버깅 도구:

고급 CORS 시나리오

기본적인 CORS 개념은 비교적 간단하지만, 고려해야 할 몇 가지 고급 시나리오가 있습니다:

CORS 모범 사례

안전하고 효율적인 CORS 구현을 보장하려면 다음 모범 사례를 따르세요:

결론

CORS는 웹 애플리케이션에서 통제된 교차 출처 요청을 가능하게 하는 중요한 보안 메커니즘입니다. CORS의 작동 방식과 올바른 구성 방법을 이해하는 것은 모든 웹 개발자에게 필수적입니다. 이 종합 가이드에 설명된 지침과 모범 사례를 따르면, 다른 출처의 리소스와 원활하게 상호 작용하는 안전하고 기능적인 웹 애플리케이션을 구축할 수 있습니다.

항상 보안을 우선시하고 지나치게 허용적인 CORS 구성을 피하는 것을 기억하세요. CORS 설정의 보안 영향을 신중하게 고려함으로써 애플리케이션과 데이터를 무단 접근으로부터 보호할 수 있습니다.

이 가이드가 CORS에 대한 궁금증을 해소하는 데 도움이 되었기를 바랍니다. 즐거운 코딩 되세요!

CORS 완전 정복: 교차 출처 리소스 공유에 대한 종합 가이드 | MLOG