티스토리 뷰

728x90

CORS 완벽 가이드: 웹 개발자를 위한 상세 설명서

안녕하세요, 개발자 여러분! 오늘은 웹 개발 세계에서 자주 마주치게 되는 그 유명한(?) CORS에 대해 깊이 있게 알아보려고 합니다. "Access to fetch at ... has been blocked by CORS policy"라는 메시지를 본 적이 있나요? 이 글을 끝까지 읽으시면, 이 오류 메시지가 더 이상 두렵지 않을 거예요.

1. CORS란 무엇인가?

CORS는 "Cross-Origin Resource Sharing"의 약자로, 한국어로는 "교차 출처 리소스 공유"라고 부릅니다. 이게 대체 무슨 말일까요?

1.1 CORS의 정의

CORS는 웹 브라우저에서 실행 중인 스크립트가 다른 출처(도메인, 프로토콜, 포트)의 리소스에 접근할 수 있게 해주는 보안 메커니즘입니다.

"CORS는 웹의 보안과 유연성 사이에서 균형을 잡는 중요한 도구입니다."

1.2 Same-Origin Policy(동일 출처 정책)

CORS를 이해하려면 먼저 Same-Origin Policy를 알아야 해요.

  • 정의: 웹 브라우저가 스크립트에서 다른 출처의 리소스와 상호작용하는 것을 제한하는 정책
  • 출처(Origin)의 정의: 프로토콜 + 도메인 + 포트

예를 들어:

  • https://example.com/page1https://example.com/page2는 같은 출처
  • https://example.comhttp://example.com은 다른 출처 (프로토콜이 다름)
  • https://example.comhttps://api.example.com은 다른 출처 (서브도메인이 다름)

2. CORS가 필요한 이유

여러분, CORS가 왜 필요한지 아시나요? 그 이유를 자세히 알아봅시다.

2.1 웹의 진화

초기 웹에서는 대부분의 웹사이트가 단일 도메인에서 모든 리소스를 제공했어요. 하지만 현대의 웹 애플리케이션은 여러 도메인의 리소스를 활용합니다. 예를 들어:

  • 프론트엔드: https://myapp.com
  • API 서버: https://api.myapp.com
  • 이미지 CDN: https://images.myapp.com

이런 구조에서는 다른 출처의 리소스에 접근할 필요가 생깁니다.

2.2 보안 강화

CORS는 무분별한 cross-origin 요청을 막아 보안을 강화합니다. 서버가 명시적으로 허용한 출처의 요청만 받아들이도록 합니다.

2.3 유연성 제공

필요한 경우, 특정 도메인의 접근을 허용할 수 있어 API 등의 리소스를 안전하게 공유할 수 있습니다.

3. CORS가 없다면? 발생할 수 있는 보안 문제

CORS가 없다면 어떤 일이 벌어질까요? 몇 가지 시나리오를 통해 알아봅시다.

3.1 크로스 사이트 스크립팅 (XSS) 공격의 확대

XSS 공격은 악성 스크립트를 웹 페이지에 주입하는 공격입니다. CORS가 없다면:

  • 공격자가 악성 스크립트를 통해 다른 도메인의 민감한 데이터에 무단으로 접근할 수 있습니다.
  • 예: 사용자가 evil.com을 방문했을 때, 이 사이트의 스크립트가 bank.com의 데이터를 읽어올 수 있습니다.
// evil.com의 악성 스크립트
fetch('https://bank.com/api/account-balance')
  .then(response => response.json())
  .then(data => {
    // 사용자의 계좌 잔고를 evil.com으로 전송
    sendToEvilServer(data);
  });

3.2 CSRF (Cross-Site Request Forgery) 공격의 용이성

CSRF는 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹사이트에 요청하게 하는 공격입니다.

  • CORS가 없다면, 모든 cross-origin 요청이 허용되어 CSRF 공격이 더 쉬워집니다.
  • 예: 사용자가 evil.com을 방문했을 때, 이 사이트가 사용자 모르게 bank.com에 송금 요청을 보낼 수 있습니다.
<!-- evil.com의 HTML -->
<img src="https://bank.com/api/transfer?amount=1000&to=evil" style="display:none" />

3.3 정보 유출의 위험

CORS가 없으면 어떤 웹사이트든 다른 웹사이트의 리소스에 무단으로 접근할 수 있습니다.

  • 개인정보, 기업 비밀 등이 유출될 위험이 높아집니다.
  • 예: 경쟁사의 웹사이트가 당신의 회사 내부 API에 접근하여 중요 데이터를 빼갈 수 있습니다.

4. CORS의 작동 방식

자, 이제 CORS가 어떻게 작동하는지 자세히 알아볼까요?

4.1 단순 요청 (Simple Requests)

일부 HTTP 요청은 별도의 확인 절차 없이도 실행됩니다. 이를 단순 요청이라고 해요. 다음 조건을 만족해야 합니다:

  1. GET, HEAD, POST 중 하나의 메서드를 사용
  2. 수동으로 설정할 수 있는 헤더는 Fetch 명세에서 정의한 CORS-safelisted request-header에 포함되는 헤더만 사용
  3. Content-Type 헤더는 다음 값들만 허용:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

단순 요청의 과정:

  1. 브라우저가 Origin 헤더와 함께 요청을 보냅니다.
  2. GET /api/data HTTP/1.1 Host: api.example.com Origin: https://myapp.com
  3. 서버가 적절한 CORS 헤더와 함께 응답합니다.
  4. HTTP/1.1 200 OK Access-Control-Allow-Origin: https://myapp.com Content-Type: application/json {"data": "Some data"}
  5. 브라우저는 Access-Control-Allow-Origin 헤더를 검사하여 요청을 허용할지 결정합니다.

4.2 프리플라이트 요청 (Preflight Requests)

단순 요청이 아닌 경우, 브라우저는 먼저 OPTIONS 메서드를 사용해 프리플라이트 요청을 보냅니다.

프리플라이트 요청의 과정:

  1. 브라우저가 OPTIONS 요청을 보냅니다.
  2. OPTIONS /api/data HTTP/1.1 Host: api.example.com Origin: https://myapp.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type
  3. 서버가 허용되는 메서드와 헤더를 포함하여 응답합니다.
  4. HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://myapp.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: Content-Type Access-Control-Max-Age: 86400
  5. 프리플라이트 요청이 성공하면, 브라우저는 원래의 요청을 보냅니다.
sequenceDiagram
    participant Client as 클라이언트 (브라우저)
    participant Server as 서버 (다른 출처)

    Note over Client,Server: 프리플라이트 요청 (OPTIONS)
    Client->>Server: OPTIONS /api/data
    Note right of Client: Origin: https://example.com<br/>Access-Control-Request-Method: POST<br/>Access-Control-Request-Headers: Content-Type

    Server-->>Client: 200 OK
    Note left of Server: Access-Control-Allow-Origin: https://example.com<br/>Access-Control-Allow-Methods: POST, GET, OPTIONS<br/>Access-Control-Allow-Headers: Content-Type<br/>Access-Control-Max-Age: 86400

    Note over Client,Server: 실제 요청 (POST)
    Client->>Server: POST /api/data
    Note right of Client: Origin: https://example.com<br/>Content-Type: application/json

    Server-->>Client: 200 OK
    Note left of Server: Access-Control-Allow-Origin: https://example.com<br/>Content-Type: application/json

    Note over Client: 클라이언트가 응답 처리

5. CORS 문제 해결하기

CORS 오류를 만났다고요? 걱정 마세요. 해결 방법을 알려드릴게요.

5.1 서버 측 설정

가장 권장되는 방법은 서버에서 적절한 CORS 헤더를 설정하는 것입니다.

Node.js와 Express를 사용한 예:

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

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

// 라우트 설정
app.get('/api/data', (req, res) => {
  res.json({ message: "This is your data!" });
});

app.listen(3000, () => console.log('Server running on port 3000'));

5.2 프록시 사용

개발 환경에서는 프록시를 사용하여 CORS 문제를 우회할 수 있습니다.

Create React App의 프록시 기능 예:

package.json에 다음 내용을 추가합니다:

{
  "proxy": "https://api.example.com"
}

이렇게 하면 개발 서버가 API 요청을 프록시하여 CORS 문제를 해결합니다.

5.3 CORS 브라우저 확장 프로그램 사용 (개발용)

주의: 이 방법은 오직 개발 목적으로만 사용해야 합니다. 프로덕션 환경에서는 절대 사용하지 마세요!

Chrome의 "Allow CORS: Access-Control-Allow-Origin" 같은 확장 프로그램을 사용하면 CORS 제한을 일시적으로 비활성화할 수 있습니다.

6. CORS 모범 사례

CORS를 효과적으로 사용하기 위한 몇 가지 팁을 드리겠습니다:

  1. 구체적인 origin 지정: Access-Control-Allow-Origin: * 대신 구체적인 도메인을 지정하세요.
  2. 필요한 메서드만 허용: Access-Control-Allow-Methods에 필요한 HTTP 메서드만 나열하세요.
  3. credentials 주의: Access-Control-Allow-Credentials: true를 사용할 때는 특히 주의하세요.
  4. 캐싱 활용: Access-Control-Max-Age 헤더로 프리플라이트 요청의 결과를 캐시하여 성능을 향상시키세요.
  5. 보안 검토: CORS 설정을 정기적으로 검토하고 필요 이상으로 개방적이지 않은지 확인하세요.

결론

CORS는 처음에는 복잡해 보일 수 있지만, 이해하고 나면 웹의 보안을 위해 꼭 필요한 메커니즘이라는 것을 알 수 있습니다. 개발자로서 CORS를 제대로 이해하고 다루는 것은 안전하고 효율적인 웹 애플리케이션을 만드는 데 필수적입니다.

CORS 오류에 직면했을 때, 당황하지 마세요. 이 글에서 설명한 단계들을 차근차근 따라가보세요. 곧 여러분도 CORS 전문가가 될 수 있을 거예요!

"웹 개발에서 CORS를 이해하는 것은 단순한 문제 해결을 넘어, 더 안전한 웹을 만드는 데 기여하는 일입니다."

이 글이 여러분의 CORS 여정에 도움이 되었기를 바랍니다. CORS는 복잡해 보이지만, 웹의 보안과 기능성을 위해 꼭 필요한 요소입니다. 이제 여러분은 CORS의 개념, 필요성, 작동 방식, 그리고 문제 해결 방법에 대해 깊이 있게 이해하셨을 것입니다.

앞으로 웹 개발을 하면서 CORS 관련 문제를 만나더라도, 이제는 자신 있게 대처할 수 있을 거예요. CORS는 단순한 장애물이 아니라, 우리가 더 안전하고 효율적인 웹 애플리케이션을 만들 수 있게 해주는 도구라는 점을 기억하세요.

마지막으로, CORS 설정은 항상 보안과 밀접한 관련이 있다는 점을 명심하세요. 필요 이상으로 개방적인 CORS 정책은 보안 취약점이 될 수 있습니다. 항상 최소 권한의 원칙을 따라 필요한 만큼만 접근을 허용하는 것이 좋습니다.

728x90
댓글