Web Server - Proxy와 Reverse Proxy

Proxy(프록시)와 Reverse Proxy(리버스 프록시)는 Client-Server model에서 익명성(Anonymity)과 성능/보안(Performance/Security)을 제공하는 핵심 기술입니다.

직관적 이해

  • 클라이언트 보호 중심: Proxy = 비서(Secretary)
  • 서버 보호 중심: Reverse Proxy = 리셉션(Front Desk)

요약

구분 익명성 (Anonymity) 성능/보안 (Performance & Security)
Proxy (Forward Proxy) - 클라이언트 IP 숨김- 웹 필터링(접속 기록 은폐) - 클라이언트 접근 제한 지역 우회 - 캐싱(Cache)으로 응답 속도 향상 - 기업 방화벽에서 트래픽 모니터링
Reverse Proxy - 서버의 실제 IP/구조 은폐 - 클라이언트는 단일 리셉션만 인식 - 로드 밸런싱(Load Balancing) - SSL 종료(TLS Termination) - DDoS 완화 및 WAF(Web Application Firewall)

Proxy와 Reverse Proxy는 겉으로 보기엔 단순히 트래픽을 ‘우회’시키는 것 같지만 목적이 다릅니다.

  • Proxy는 사용자(클라이언트)의 익명성 확보와 제어가 핵심이며,
  • Reverse Proxy는 서버의 보안 강화와 성능 최적화에 중점을 둡니다.

Webhook (웹훅)

  • 정의: 으로, Sender (발신 서버 A)가 특정 이벤트 발생 시 다른 Receiver(수신 서버 B)에 HTTP 에 따른 요청(주로 POST)을 보내 알림 또는 데이터를 전달하는 “Event (trigger) 기반 서버 간 통신 방식”. 이때 주고받는 데이터는 주로 JSON(JavaScript Object Notation) 포맷을 사용합니다.
  • 동작 방식:
  • Sender-Receiver 구조:
  • Webhook 방식 vs Polling with APIs 방식
구분 Webhook (웹훅) Polling with APIs
방식 A 서버가 이벤트 발생 시 자동으로 B 서버에 전송 B 서버가 일정 주기로 A 서버에 이벤트가 있는지 직접 요청
효율성 이벤트가 있을 때만 전송, 효율적 불필요한 요청이 많아 서버 리소스 낭비
실시간성 실시간 알림 가능 실시간이 아님

예시: Webhook 통신 흐름

  1. Sender (A 서버)에서 이벤트 발생 (예: 사용자가 상품을 결제).
  2. Sender가 Receiver (B 서버)의 Webhook URL(예: https://a-server.com/webhook)로 HTTP POST 요청을 전송.
  3. Receiver는 POST Body의 JSON 데이터를 파싱하여 처리(DB 저장, 알림 발송 등).
  4. Receiver는 성공 여부를 HTTP 응답 코드(예: 200 OK)로 반환.

Sender(A 서버)가 B 서버로 보내는 데이터 (JSON 파일 형식):

json
{
  "event": "payment_completed",
  "timestamp": "2025-07-26T09:23:15Z",
  "data": {
    "payment_id": "pay_123456789",
    "user": {
      "id": "user_98765",
      "email": "user@example.com",
      "name": "Alice Kim"
    },
    "amount": 49900,
    "currency": "KRW",
    "status": "success"
  },
  "signature": "f3b9a8d8a4e... (HMAC-SHA256)"
}
  • event: 어떤 이벤트가 발생했는지 명시 (예: payment_completed).
  • timestamp: 이벤트가 발생한 시간 (ISO 8601 형식).
  • data: 이벤트와 관련된 상세 데이터.
  • signature: 보안 검증용 HMAC 서명 값. Sender가 Webhook Payload를 해싱(HMAC-SHA256)하여 A 서버가 데이터 위변조 여부를 검증할 수 있도록 전달.

Receiver (B 서버)의 Webhook 엔드포인트 (Python Flask 예시):

python
from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
SECRET_KEY = b'shared_secret_key'

@app.route('/webhook', methods=['POST'])
def webhook_receiver():
    # 요청 데이터(JSON) 파싱
    payload = request.get_data()
    received_signature = request.json.get('signature')

    # HMAC-SHA256 서명 검증
    expected_signature = hmac.new(SECRET_KEY, payload, hashlib.sha256).hexdigest()
    if received_signature != expected_signature:
        return jsonify({"message": "Invalid signature"}), 403

    # 실제 이벤트 데이터 처리
    event = request.json.get('event')
    data = request.json.get('data')

    print(f"Webhook event: {event}, data: {data}")
    return jsonify({"message": "Webhook received"}), 200

if __name__ == '__main__':
    app.run(port=5000)

JSON vs curl의 차이

구분 JSON 포맷 curl 포맷
목적 Webhook 요청 Body 내용만 설명 실제 HTTP 요청(헤더 + Body)을 커맨드라인에서 실행 가능
구성 순수 데이터 구조 (Key-Value) HTTP 메서드(-X), 헤더(-H), 데이터(-d) 등을 명시
용도 Sender가 보내는 Payload의 내부 구조 확인 Receiver에 직접 테스트 요청 전송 시 활용

Webhook 요청(JSON 예시)

Sender(A 서버)가 B 서버의 엔드포인트(https://a-server.com/webhook)로 HTTP POST 요청을 보낼 때, Body(본문*를 JSON 형식으로 보냅니다.

json
{
  "event": "payment_completed",
  "timestamp": "2025-07-26T09:23:15Z",
  "data": {
    "payment_id": "pay_123456789",
    "user": {
      "id": "user_98765",
      "email": "user@example.com",
      "name": "Alice Kim"
    },
    "amount": 49900,
    "currency": "KRW",
    "status": "success"
  },
  "signature": "f3b9a8d8a4e... (HMAC-SHA256)"
}

동일 요청을 curl로 표현

Webhook은 단순히 HTTP 요청이므로, curl 명령어로 쉽게 시뮬레이션할 수 있습니다.

shell
curl -X POST "https://a-server.com/webhook" \
     -H "Content-Type: application/json" \
     -H "X-Signature: f3b9a8d8a4e... (HMAC-SHA256)" \
     -d '{
           "event": "payment_completed",
           "timestamp": "2025-07-26T09:23:15Z",
           "data": {
             "payment_id": "pay_123456789",
             "user": {
               "id": "user_98765",
               "email": "user@example.com",
               "name": "Alice Kim"
             },
             "amount": 49900,
             "currency": "KRW",
             "status": "success"
           }
         }'