Network / / 2024. 9. 27. 16:23

CORS, WebSocket, 그리고 Base64

**CORS (Cross-Origin Resource Sharing)**는 웹 브라우저에서 다른 도메인의 자원에 접근할 수 있도록 해주는 보안 메커니즘이야. 기본적으로 웹 브라우저는 보안상의 이유로 **동일 출처 정책(Same-Origin Policy)**을 적용해서, 다른 도메인, 프로토콜, 또는 포트에서 자원에 접근하는 것을 제한해. CORS는 이 제한을 완화하는 역할을 해.

 

**동일 출처 정책(Same-Origin Policy)**란?

 

동일 출처 정책은 웹 브라우저의 보안 정책 중 하나로, 한 출처에서 로드된 웹 페이지가 다른 출처의 자원에 접근하는 것을 제한하는 규칙이야. 여기서 **출처(Origin)**는 도메인, 프로토콜, 포트로 구성돼. 예를 들어, 다음 두 URL은 서로 다른 출처로 간주돼:

 

 https://example.com

 http://example.com (프로토콜이 다름)

 https://api.example.com (도메인이 다름)

 https://example.com:8080 (포트가 다름)

 

CORS의 필요성:

 

동일 출처 정책은 보안을 위해 중요하지만, 실제 웹 애플리케이션 개발에서는 다른 도메인에서 데이터를 가져와야 할 때가 많아. 예를 들어, 프론트엔드 애플리케이션에서 외부 API를 호출하거나, 다른 서버에서 데이터를 가져올 때 말이지. 이때 CORS를 설정하면 다른 출처의 자원에 안전하게 접근할 수 있어.

 

CORS 동작 원리:

 

CORS는 HTTP 헤더를 사용해서 브라우저와 서버 간의 권한을 부여하는 방식으로 동작해. 서버는 요청을 보낸 도메인이 허용된 출처인지 확인하고, 맞으면 해당 요청을 처리하도록 응답해.

 

1. 클라이언트가 서버에 요청을 보낼 때, 웹 브라우저는 출처(Origin) 헤더를 포함해.

2. 서버는 이 요청을 받고, Access-Control-Allow-Origin 헤더를 통해 허용된 출처를 응답으로 보냄.

3. 만약 서버가 응답에서 허용된 출처를 지정하면, 브라우저는 자원을 사용할 수 있게 돼.

 

기본 요청 예시:

GET /api/data
Origin: https://mydomain.com

 

서버 응답:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mydomain.com

 

CORS 요청 종류:

 

1. 단순 요청(Simple Request):

 GET, POST, HEAD 메서드로 요청하는 경우, 그리고 요청에 추가적인 헤더나 쿠키 등이 없을 때.

 이 경우, 브라우저는 자동으로 요청을 보내고, 서버가 Access-Control-Allow-Origin 헤더로 응답하면 자원을 사용할 수 있어.

2. 프리플라이트 요청(Preflight Request):

 브라우저가 안전하지 않은 요청(예: PUT, DELETE, 또는 커스텀 헤더 포함)이나 쿠키를 동반한 요청을 보내기 전에, 서버에 OPTIONS 메서드로 프리플라이트(preflight) 요청을 보내서 서버가 해당 요청을 허용하는지 미리 확인해.

 프리플라이트 요청은 브라우저가 자동으로 보내며, 서버가 이를 승인해야 이후 실제 요청이 진행돼.

 

프리플라이트 요청 예시:

OPTIONS /api/data
Origin: https://mydomain.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

 

서버 응답:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mydomain.com
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: Content-Type

 

CORS 요청 종류:

 

1. 단순 요청(Simple Request):

 GET, POST, HEAD 메서드로 요청하는 경우, 그리고 요청에 추가적인 헤더나 쿠키 등이 없을 때.

 이 경우, 브라우저는 자동으로 요청을 보내고, 서버가 Access-Control-Allow-Origin 헤더로 응답하면 자원을 사용할 수 있어.

2. 프리플라이트 요청(Preflight Request):

 브라우저가 안전하지 않은 요청(예: PUT, DELETE, 또는 커스텀 헤더 포함)이나 쿠키를 동반한 요청을 보내기 전에, 서버에 OPTIONS 메서드로 프리플라이트(preflight) 요청을 보내서 서버가 해당 요청을 허용하는지 미리 확인해.

 프리플라이트 요청은 브라우저가 자동으로 보내며, 서버가 이를 승인해야 이후 실제 요청이 진행돼.

 

프리플라이트 요청 예시:

OPTIONS /api/data
Origin: https://mydomain.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

 

서버 응답:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mydomain.com
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: Content-Type

 

3. 자격 증명 있는 요청(Credentialed Request):

 쿠키나 HTTP 인증 정보 같은 **자격 증명(Credentials)**을 포함한 요청. 이 경우, 서버는 Access-Control-Allow-Credentials: true 헤더를 통해 자격 증명을 허용할 수 있어야 해.

 

자격 증명 있는 요청 예시:

GET /api/data
Origin: https://mydomain.com
Cookie: sessionId=1234

 

서버 응답:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mydomain.com
Access-Control-Allow-Credentials: true

 

CORS 주요 헤더:

 

1. Access-Control-Allow-Origin:

 요청을 허용할 출처(도메인)를 지정해. *를 사용하면 모든 출처에서의 요청을 허용할 수 있지만, 자격 증명이 포함된 요청에서는 사용할 수 없어.

2. Access-Control-Allow-Methods:

 서버가 허용하는 HTTP 메서드(예: GET, POST, PUT, DELETE)를 지정해. 이 헤더는 프리플라이트 요청에 응답할 때 사용됨.

3. Access-Control-Allow-Headers:

 클라이언트가 요청에 포함할 수 있는 허용된 헤더 목록을 지정해. 이 헤더 역시 프리플라이트 요청에서 사용돼.

4. Access-Control-Allow-Credentials:

 자격 증명이 포함된 요청(예: 쿠키, 인증 정보)을 허용할지 여부를 지정해. true 값이 설정되면 허용됨.

5. Access-Control-Max-Age:

 프리플라이트 요청에 대한 결과를 브라우저가 캐시할 시간을 초 단위로 설정해. 이 값이 클수록 프리플라이트 요청을 자주 보내지 않게 돼.

 

CORS의 장점:

 

1. 보안 강화:

 동일 출처 정책과 함께 동작해서, 다른 도메인의 악의적인 요청을 막아줘.

2. 유연성 제공:

 허용된 출처를 명시적으로 설정하여, 특정 출처에만 자원 접근 권한을 줄 수 있어. 이로 인해 개발자들은 외부 API나 여러 도메인 간의 협력을 안전하게 관리할 수 있어.

 

CORS 설정의 예시 (서버 측):

 

Node.js (Express):

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

// 모든 도메인 허용
app.use(cors());

// 특정 도메인만 허용
app.use(cors({
  origin: 'https://mydomain.com',
  credentials: true // 자격 증명 허용
}));

app.get('/api/data', (req, res) => {
  res.json({ message: 'CORS 설정 완료!' });
});

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

 

Spring Boot:

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

@RestController
public class MyController {

    @CrossOrigin(origins = "https://mydomain.com")
    @GetMapping("/api/data")
    public String getData() {
        return "CORS 설정 완료!";
    }
}

 

CORS 문제 해결 방법:

 

CORS와 관련된 문제는 보통 클라이언트가 허용되지 않은 출처에서 서버 자원에 접근하려고 할 때 발생해. 이를 해결하려면 서버 측에서 Access-Control-Allow-Origin 헤더를 올바르게 설정해 줘야 해.

 

 클라이언트에서 요청할 때 CORS 오류가 발생하면, 서버에서 적절한 헤더를 설정했는지 확인해야 해.

 서버가 요청을 허용하도록 설정이 되어 있지 않으면, 브라우저에서 CORS 정책 위반 오류가 발생할 수 있어.

 

요약:

 

 CORS는 웹 브라우저가 다른 출처의 자원에 접근할 때, 해당 요청을 서버가 허용할 수 있도록 해주는 보안 메커니즘이야.

 서버는 Access-Control-Allow-Origin과 같은 CORS 헤더를 통해 클라이언트의 요청을 허용할 수 있어.

 CORS는 동일 출처 정책을 완화하면서도, 웹 애플리케이션의 보안을 유지해줌.

 CORS는 프리플라이트 요청을 통해 서버가 특정 요청을 허용할지 여부를 확인할 수 있는 과정을 포함해.


**웹소켓(WebSocket)**은 클라이언트와 서버 간의 양방향 통신을 가능하게 하는 프로토콜로, 웹 애플리케이션에서 실시간 데이터 전송을 효율적으로 처리할 수 있어. 웹소켓의 특징은 HTTP 기반의 요청-응답 방식과는 다르게, 한 번 연결이 성립되면 클라이언트와 서버가 지속적으로 데이터를 주고받을 수 있다는 것이야.

 

하지만, 웹소켓은 클라이언트와 서버 간의 통신뿐만 아니라 서버 간 통신에도 사용할 수 있어. 이로 인해, 서버들 간에 실시간 데이터를 동기화하거나 빠르게 처리해야 할 때 매우 유용해.

 

웹소켓의 주요 특징

 

1. 양방향 통신: 클라이언트와 서버, 서버와 서버 간 모두 양방향으로 데이터를 주고받을 수 있어. 서버에서 클라이언트로 데이터를 푸시(push)하거나, 클라이언트에서 서버로 요청하는 방식과 달리, 언제든지 데이터 전송이 가능해.

2. 실시간 데이터 전송: 웹소켓은 데이터 전송 시 **지연 시간(Latency)**이 적고, 실시간성이 중요한 애플리케이션(예: 실시간 채팅, 게임, 주식 거래 등)에 적합해.

3. 지속적인 연결: 클라이언트와 서버가 한 번 연결되면 그 연결을 유지하면서 데이터를 주고받기 때문에, 매번 새로운 연결을 만들 필요가 없어. 이는 네트워크 자원 절약에 매우 효율적이야.

4. 낮은 오버헤드: HTTP와 다르게, 웹소켓은 연결을 맺고 나면 데이터 전송에 필요한 헤더 정보가 최소화돼서, 불필요한 네트워크 자원을 낭비하지 않지.

 

서버 간 웹소켓 통신

 

웹소켓은 서버와 서버 간에도 통신할 수 있다는 점에서 매우 강력해. 두 서버가 실시간으로 데이터를 주고받아야 하거나, 빠르게 처리해야 할 때 서버 간의 웹소켓 통신이 유용해.

 

예를 들어, 여러 서버가 각각의 클라이언트 요청을 처리하고 그 결과를 실시간으로 다른 서버들과 공유해야 할 때, 웹소켓을 사용해 서버 간 통신을 원활하게 할 수 있어. 이 방식은 마이크로서비스 아키텍처나 실시간 데이터 분석에서 특히 유용하지.

 

웹소켓의 사용 사례

 

1. 실시간 채팅: 클라이언트와 서버가 웹소켓을 사용해 실시간으로 메시지를 주고받을 수 있어. 메시지가 발생할 때마다 서버는 즉시 다른 클라이언트에게 해당 메시지를 푸시할 수 있어.

2. 실시간 게임: 웹소켓은 빠르게 변하는 게임 환경에서 실시간으로 위치, 상태 등의 데이터를 교환하는 데 적합해.

3. 주식 거래: 주식 가격, 거래 내역 등을 실시간으로 업데이트하기 위해 서버 간, 또는 서버와 클라이언트 간에 웹소켓을 활용해 즉각적인 데이터 전송이 가능해.

4. IoT(사물인터넷): 다양한 IoT 장치가 서버와 실시간으로 통신하며 데이터를 주고받을 때 웹소켓이 유용해. 여러 장치에서 발생하는 데이터를 서버에 전달하고, 서버에서 이를 처리해 다시 장치로 실시간으로 피드백을 줄 수 있어.

웹소켓(WebSocket) 요약

특징설명

양방향 통신 클라이언트와 서버 간 양방향 실시간 통신이 가능. 클라이언트와 서버가 데이터를 자유롭게 주고받을 수 있음.
실시간 데이터 전송 데이터 전송 시 지연 시간이 적고, 실시간 통신에 매우 적합함. 채팅, 게임, 주식 거래 등에서 사용.
지속적인 연결 한 번 연결이 성립되면 클라이언트와 서버 간 연결을 유지하며, 매번 새롭게 연결하지 않음.
낮은 오버헤드 HTTP 요청과 달리, 헤더 정보가 작아 네트워크 자원을 절약할 수 있음.

웹소켓 사용 사례

사례설명

실시간 채팅 클라이언트가 서버로 메시지를 보내고, 서버는 실시간으로 다른 클라이언트에 메시지를 전달함.
실시간 게임 게임 내에서 실시간으로 위치나 상태 정보를 빠르게 교환해야 할 때 사용.
주식 거래 실시간으로 주식 가격이나 거래 내역을 즉시 업데이트하는 데 사용.
IoT IoT 장치가 서버와 실시간으로 데이터를 주고받는 데 활용.

웹소켓 vs HTTP 비교

항목웹소켓HTTP

통신 방식 양방향 통신 가능 단방향 요청-응답
연결 유지 지속적인 연결 요청 시마다 새로운 연결
헤더 오버헤드 작음
실시간성 실시간 통신 가능 실시간 통신 어려움 (Polling 필요)

웹소켓의 장단점

구분설명

장점
  • 실시간 통신 가능
  • 낮은 오버헤드로 네트워크 자원 절약
  • 효율적인 네트워크 사용
단점
  • 서버 리소스 사용 증가
  • 복잡한 서버 구성 필요

서버 간 웹소켓 통신

특징설명

서버 간 실시간 데이터 처리 서버와 서버 간에도 양방향 실시간 데이터 통신이 가능함.
마이크로서비스 통신 여러 마이크로서비스가 실시간으로 데이터를 동기화하거나 주고받을 때 사용됨.

 

웹소켓과 HTTP의 차이점

 

웹소켓과 HTTP는 모두 웹 애플리케이션에서 사용되지만, 그 방식은 다르지:

 

 HTTP: 요청과 응답의 단방향 통신 방식. 클라이언트가 서버에 요청을 보내면 서버는 그 요청에 응답한 뒤 연결을 끊음.

 웹소켓: 양방향 통신이 가능하며, 한 번 연결되면 그 연결이 지속돼. 서버는 클라이언트가 요청하지 않아도 실시간으로 데이터를 푸시할 수 있어.

 

웹소켓의 장단점

 

장점:

 

 실시간 통신: 양방향 실시간 통신이 가능해, 빠르게 변하는 데이터를 처리해야 하는 애플리케이션에 적합해.

 낮은 오버헤드: HTTP처럼 매번 헤더 정보를 주고받을 필요가 없어서, 네트워크 자원을 효율적으로 사용할 수 있어.

 효율적인 네트워크 자원 사용: 웹소켓은 지속적인 연결을 통해 불필요한 재연결을 줄이고, 네트워크 부하를 줄일 수 있어.

 

단점:

 

 서버 리소스 사용 증가: 지속적인 연결을 유지해야 하므로, 많은 클라이언트가 연결되면 서버의 리소스를 많이 사용하게 돼.

 복잡한 서버 구현: HTTP 요청-응답 방식보다 복잡한 서버 구성이 필요해. 특히 서버가 많은 연결을 관리해야 하므로 적절한 리소스 관리가 필수적이야.

 

결론

 

웹소켓은 클라이언트와 서버, 서버와 서버 간 양방향 실시간 통신을 지원하는 강력한 프로토콜이야. 실시간 데이터 처리가 필수적인 애플리케이션에 적합하며, 연결 유지와 빠른 응답 속도를 통해 효율적인 네트워크 사용이 가능해. 서버 간 실시간 동기화, 마이크로서비스 간의 빠른 통신에도 활용될 수 있으며, HTTP보다 실시간성이 요구되는 애플리케이션에서 큰 장점을 제공해.


Base64 이진 데이터(바이너리 데이터), 즉 010101010 같은 2진수 데이터를 텍스트로 변환하는 방식이야. 이진 데이터를 직접 전송하거나 저장하기 어려운 경우가 있어서, 이를 사람이 읽을 수 있는 텍스트 형식으로 변환해주는 거지.

 

Base64의 동작 방식:

 

1. 이진 데이터를 가져와서 8비트씩 잘라(예를 들어, 01010101 같은 8비트).

2.  8비트 데이터를 6비트씩 나눠서 각 6비트 데이터를 Base64의 문자로 변환해.

 6비트는 0부터 63까지의 값을 표현할 수 있고, Base64는 이 값에 대응하는 64개의 문자(영문 대문자, 소문자, 숫자, +, /)를 사용해 변환해.

3. 남은 비트는 **패딩 문자 =**로 채워서 처리해.

 

이 과정을 통해 이진 데이터를 텍스트로 변환하게 되는 거야.

 

왜 Base64를 쓰는가?

 

1. 이진 데이터는 일부 시스템에서 직접 처리하기 어려울 수 있어(예: 이메일 전송, URL에 포함하는 경우 등). 그래서 Base64로 변환해 텍스트 형식으로 전송하거나 저장하면 안전하게 처리할 수 있어.

2. Base64로 인코딩하면 모든 데이터가 ASCII 문자로 변환되기 때문에 문자 기반 시스템에서 안정적으로 다룰 수 있게 돼.

 

예시:

 

만약 이진 데이터 01000001(A의 ASCII 값)이라면, 이를 Base64로 변환하면 **텍스트 “A”**로 변환되는 방식이야.

 

정리:

 

 Base64 이진 데이터를 텍스트로 변환하는 방식이야.

 이를 통해 텍스트 기반 시스템에서도 이진 데이터를 안전하게 전송하거나 저장할 수 있어.

 8비트 이진 데이터를 6비트씩 나누어, 64개의 ASCII 문자로 변환해 텍스트로 만들어.

'Network' 카테고리의 다른 글

HoL Blocking, Pipelining, Multiplexing  (1) 2024.10.10
Https 프로토콜  (3) 2024.09.27
Http 프로토콜  (5) 2024.09.27
UDP 소켓 프로그래밍  (0) 2024.09.26
TCP 소켓 프로그래밍  (0) 2024.09.26
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유