테마 전환

프런트엔드에 노출된 API Key 도용 방지: Workers 프록시로 5분 만에 키 보호, 하루 10만 회 무료

Easton editorial illustration: service topology model

ChatGPT API를 호출하는 작은 도구를 만들면서 API Key를 프런트엔드 코드에 직접 넣었습니다. 그 결과 다음 날 계정에서 300위안 넘는 금액이 무단으로 사용되었습니다. 하룻밤 사이 호출이 수천 번 발생한 것입니다. 환경 변수도 해결책이 아니었습니다. Vite나 Webpack의 환경 변수는 결국 JS 파일에 번들링되기 때문에 사용자가 Network 패널을 열면 전체 요청을 확인할 수 있습니다.

일반적인 해결책은 프록시용 백엔드 서버를 구축하는 것이지만 서버 비용이 들고 환경, SSL 인증서, CORS까지 설정해야 합니다. Cloudflare Workers를 사용하면 5분 만에 API 프록시를 배포할 수 있고 API Key는 서버 측 환경 변수에 보관되어 프런트엔드에 전혀 노출되지 않습니다. 하루 10만 회 요청까지 완전히 무료입니다. 이 글에서는 그 구축 방법을 설명합니다.

API Key를 프런트엔드에 두면 안 되는 이유

프런트엔드 코드는 완전히 공개됩니다

많은 사람이 .env 파일이나 Vite의 import.meta.env를 사용하면 안전하다고 생각합니다. 하지만 이는 개발 편의를 위한 도구일 뿐이며, build 후에는 모든 환경 변수가 JS 파일에 하드코딩됩니다.

직접 확인할 수도 있습니다. 아무 프런트엔드 프로젝트의 운영 환경에서 F12로 개발자 도구를 열고 Network 패널로 이동한 뒤 페이지를 새로 고치세요. 요청 헤더, 요청 본문, URL 매개변수를 비롯한 모든 API 요청이 그대로 노출됩니다.

코드를 난독화하거나 압축해도 읽기만 조금 어려워질 뿐입니다. API를 호출하려면 실제 Key를 전송해야 하므로 이를 난독화할 수 없습니다. 암호화를 생각할 수도 있지만 암호화와 복호화 코드가 모두 프런트엔드에 있으므로 사용자도 똑같이 볼 수 있습니다.

결국 프런트엔드는 사용자의 브라우저에서 실행됩니다. 개발자가 할 수 있는 일은 사용자도 할 수 있으므로 근본적으로 해결할 수 없습니다.

도용되면 얼마나 큰 비용이 발생할까요?

저도 전에는 누가 굳이 제 코드를 뒤져 API Key를 훔치겠느냐고 생각했습니다. 하지만 인터넷에는 실제로 그런 일을 전문적으로 하는 사람이 있습니다.

GitHub에는 프로젝트를 자동으로 스캔해 코드에 노출된 API Key를 찾는 도구가 있습니다. Key를 발견한 사람은 무료 혜택을 악용하거나 다른 사람에게 판매하려고 API를 마구 호출합니다. OpenAI API는 token 단위로 과금되므로 하룻밤 사이 수백 위안이 청구되는 일이 흔하고, 심하면 수천 위안까지 나올 수 있습니다.

한 개발자 포럼에서는 누군가 AI 채팅 페이지를 만들면서 Key를 프런트엔드에 넣었다가 도용당해 무단 호출이 이어졌고, 한 달 청구액이 2,000달러를 넘었다는 이야기도 봤습니다. 나중에 이의 제기가 받아들여졌지만 그 과정 자체가 큰 스트레스였습니다.

OpenAI뿐 아니라 Google Maps API, 각종 날씨 API와 번역 API처럼 사용량 기반으로 과금되는 서비스는 모두 도용 위험이 있습니다.

기존 방식의 문제

위험을 알게 된 뒤 해결책을 찾아봤습니다. 인터넷에서 제시하는 방법은 대부분 “백엔드 서버를 구축해 프록시로 사용하라”는 것이었습니다.

말은 간단하지만 실제로는 다음과 같은 문제가 있습니다.

  • 비용: 가장 저렴한 클라우드 서버(Alibaba Cloud나 Tencent Cloud의 경량 애플리케이션 서버)도 매달 50~100위안이 듭니다. 아주 비싸지는 않지만 개인 프로젝트에는 부담스러운 비용입니다.
  • 복잡한 설정: Node.js 같은 런타임을 설치하고 Nginx 리버스 프록시를 구성하며, SSL 인증서를 발급해 HTTPS를 설정하고 CORS까지 처리해야 합니다. 이것만 이해하는 데도 반나절이 걸릴 수 있습니다.
  • 유지 관리 비용: 서버를 주기적으로 업데이트하고 상태를 모니터링해야 하며, 장애가 나면 재시작해야 합니다. 작은 프로젝트에는 지나친 부담입니다.

Alibaba Cloud Function Compute나 Tencent Cloud Functions 같은 중국 대형 사업자의 Serverless 함수는 비용을 줄일 수 있지만 설정이 더 복잡하고 콜드 스타트가 느리며 문서도 그다지 친절하지 않습니다. 저도 몇 번 시도했지만 성공하지 못했습니다.

API 게이트웨이는 전문적으로 들리지만 기업용 제품이라 개인 개발자에게는 진입 장벽이 너무 높습니다.

Cloudflare Workers 방식의 장점

완전히 무료이면서 성능도 뛰어납니다

Cloudflare Workers의 무료 한도는 하루 10만 회 요청입니다. 개인 프로젝트에는 충분한 양입니다. 제가 만든 작은 도구도 하루 호출이 수백 회뿐이라 무료 한도로 넉넉합니다.

하루 10만 회
무료 한도
개인 프로젝트에 충분한 수준
5분
배포 시간
생성부터 공개까지
월 50~100위안 절약
비용 비교
자체 서버 구축 대비

Cloudflare는 전 세계 200곳이 넘는 데이터 센터를 운영하며 코드는 이 노드들에 자동으로 배포됩니다. 사용자가 접속하면 가장 가까운 노드로 자동 라우팅되어 응답 속도가 매우 빠릅니다. 특정 지역에 서버를 구매해 다른 지역에서 느려지는 기존 방식과 다릅니다.

또 하나 중요한 점은 Workers에는 콜드 스타트 문제가 없다는 것입니다. AWS Lambda 같은 Serverless 함수는 오랫동안 요청이 없으면 다음 호출 때 시작에 몇 초가 걸릴 수 있습니다. Workers는 거의 밀리초 단위로 응답하므로 기존 서버와 비슷한 사용 경험을 제공합니다.

배포가 매우 간단합니다

처음 Workers를 사용했을 때 계정 가입부터 배포 완료까지 실제로 5분밖에 걸리지 않았습니다. 과장이 아닙니다.

서버 환경을 설정하거나 Node.js, Nginx를 설치할 필요가 없고 SSL 인증서를 신청할 필요도 없습니다. Workers가 HTTPS를 자동으로 제공합니다. 해야 할 일은 다음 세 가지뿐입니다.

  1. 코드 작성(수십 줄짜리 JS 파일 하나면 충분합니다)
  2. 명령 하나 실행: wrangler publish
  3. 완료

배포하면 Cloudflare가 your-worker.your-subdomain.workers.dev와 비슷한 도메인을 제공하므로 바로 사용할 수 있습니다. 자체 도메인을 사용하고 싶다면 콘솔에서 연결하기만 하면 되며 별도 설정은 필요 없습니다.

기존 방식과 비교하면 서버 구매 → 환경 설정 → 코드 작성 → Nginx 설정 → 인증서 발급 → 배포 → 테스트 순서입니다. 과정만 봐도 머리가 아픕니다.

CORS 문제도 자연스럽게 해결합니다

프런트엔드에서 타사 API를 호출할 때 Access to fetch at 'xxx' from origin 'yyy' has been blocked by CORS policy 같은 CORS 오류를 자주 만납니다.

이는 브라우저의 보안 제한 때문에 서로 다른 도메인 사이의 요청이 차단되어 발생합니다. 일반적으로는 API 제공자가 응답 헤더에 CORS 설정을 추가해야 하지만 타사 API의 설정을 마음대로 바꿀 수는 없습니다.

Workers를 프록시로 사용하면 깔끔하게 해결됩니다.

  • 프런트엔드는 https://api.yourdomain.com 같은 자체 Workers 주소를 호출합니다.
  • Workers가 타사 API를 호출합니다.
  • Workers가 응답을 반환할 때 CORS 헤더를 추가합니다.

브라우저 입장에서는 동일 출처 API를 호출하는 것이므로 CORS 문제가 없습니다. 타사 API 입장에서도 Workers 서버가 호출하므로 CORS 문제가 없습니다.

저도 예전에 Amap API를 호출할 때 계속 CORS 오류가 발생했지만 Workers 프록시를 사용하고 코드 두 줄을 추가해 해결했습니다.

실전: 첫 번째 API 프록시 만들기

장점은 충분히 살펴봤으니 이제 직접 구축해 보겠습니다. OpenAI API 프록시를 예로 들지만 다른 API도 방법은 거의 같습니다.

1단계: 환경 준비

1. Cloudflare 계정 가입

cloudflare.com에서 무료 계정을 만드세요. 가입 절차는 간단하며 이메일 인증만 하면 됩니다.

2. Wrangler CLI 설치

Wrangler는 Workers를 생성하고 배포하는 Cloudflare 공식 명령줄 도구입니다.

npm install -g wrangler

Node.js가 설치되어 있지 않다면 먼저 nodejs.org에서 내려받아 설치하세요.

3. 로그인 및 권한 승인

wrangler login

이 명령을 실행하면 권한 승인을 위한 브라우저가 열립니다. 동의하면 명령줄 도구에서 Workers를 관리할 수 있습니다.

2단계: Worker 프로젝트 생성

wrangler init openai-proxy

명령을 실행하면 몇 가지 질문이 표시됩니다.

  • “Would you like to use TypeScript?” → TS에 익숙하지 않다면 No 선택
  • “Would you like to create a new Worker?” → Yes 선택
  • “Would you like to install dependencies?” → Yes 선택

완료되면 대략 다음 구조의 프로젝트 폴더가 생성됩니다.

openai-proxy/
├── src/
│   └── index.js       # 코드를 작성할 파일
├── wrangler.toml      # 설정 파일
└── package.json

3단계: 프록시 코드 작성

src/index.js를 열고 기본 코드를 삭제한 뒤 다음 코드로 바꾸세요.

export default {
  async fetch(request, env) {
    // POST 요청만 허용
    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }
    // 환경 변수에서 OpenAI API Key 읽기
    const apiKey = env.OPENAI_API_KEY;
    if (!apiKey) {
      return new Response('API Key not configured', { status: 500 });
    }
    try {
      // 프런트엔드에서 보낸 요청 본문 가져오기
      const body = await request.json();
      // 실제 OpenAI API 호출
      const response = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`,  // 서버 측 Key 사용
        },
        body: JSON.stringify(body),
      });
      // 응답 데이터 가져오기
      const data = await response.json();
      // 프런트엔드로 반환하면서 CORS 헤더 추가
      return new Response(JSON.stringify(data), {
        status: response.status,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',  // 모든 도메인의 접근 허용
          'Access-Control-Allow-Methods': 'POST',
          'Access-Control-Allow-Headers': 'Content-Type',
        },
      });
    } catch (error) {
      return new Response(JSON.stringify({ error: error.message }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
      });
    }
  },
};

코드는 매우 간단합니다.

  1. 프런트엔드의 POST 요청을 받습니다.
  2. 환경 변수에서 실제 API Key를 읽습니다. 이 Key는 프런트엔드에서 절대 볼 수 없습니다.
  3. 이 Key로 OpenAI API를 호출합니다.
  4. 결과를 프런트엔드로 반환하면서 CORS 헤더를 추가해 교차 출처 문제를 해결합니다.

4단계: Secrets 설정(API Key 보관)

가장 중요한 단계입니다. API Key를 코드에 작성하지 말고 Cloudflare의 Secrets 기능으로 암호화해 보관해야 합니다.

다음 명령을 실행하세요.

wrangler secret put OPENAI_API_KEY

Enter를 누르면 Key 값을 입력하라는 메시지가 표시됩니다. OpenAI API Key를 붙여 넣고 다시 Enter를 누르세요.

이 Key는 Cloudflare 서버에 암호화되어 저장되며 콘솔에서도 평문을 볼 수 없습니다. 코드에서는 env.OPENAI_API_KEY로 읽을 수 있습니다.

로컬 개발에서는 어떻게 하나요?

프로젝트 루트에 .dev.vars 파일을 만드세요.

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx

이 파일은 로컬 개발에서만 사용하므로 절대 Git에 커밋하지 마세요. .gitignore에 다음 한 줄을 추가합니다.

.dev.vars

5단계: 로컬 테스트

프로젝트 디렉터리에서 다음 명령을 실행하세요.

wrangler dev

기본적으로 http://localhost:8787에 로컬 서버가 시작됩니다. Postman이나 프런트엔드 코드로 테스트할 수 있습니다.

fetch('http://localhost:8787', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model: 'gpt-3.5-turbo',
    messages: [{ role: 'user', content: 'Hello!' }],
  }),
})
  .then(res => res.json())
  .then(data => console.log(data));

OpenAI 응답이 정상적으로 반환되면 프록시가 제대로 작동하는 것입니다.

6단계: 운영 환경에 배포

테스트에 문제가 없다면 명령 하나로 배포할 수 있습니다.

wrangler publish

몇 초면 완료됩니다. 배포가 끝나면 Cloudflare가 다음과 비슷한 주소를 제공합니다.

https://openai-proxy.your-subdomain.workers.dev

프런트엔드 코드의 API 주소를 이 주소로 바꾸면 끝입니다. API Key는 프런트엔드에 전혀 노출되지 않습니다.

자체 도메인을 사용하려면 Cloudflare 콘솔의 Workers 페이지에서 해당 Worker → Settings → Triggers → Add Custom Domain으로 이동해 api.yourdomain.com 같은 도메인을 입력하고 안내에 따라 DNS를 설정하면 됩니다.

고급 팁과 모범 사례

위 코드는 바로 실행할 수 있지만 더 개선할 부분도 있습니다. 몇 가지 고급 팁을 소개합니다.

프록시 악용 방지

현재 Worker는 공개되어 있어 주소를 아는 사람이라면 누구나 호출할 수 있습니다. 누군가 악의적으로 API를 반복 호출하면 무료 한도를 빠르게 소진할 수 있고 심하면 비용까지 발생합니다.

간단한 Token 검증

다음과 같은 간단한 검증 절차를 추가할 수 있습니다.

export default {
  async fetch(request, env) {
    // 요청 헤더의 token 검증
    const token = request.headers.get('X-API-Token');
    if (token !== env.MY_SECRET_TOKEN) {
      return new Response('Unauthorized', { status: 401 });
    }
    // ... 이후 프록시 로직
  },
};

그런 다음 wrangler secret put MY_SECRET_TOKEN으로 비밀 값을 설정합니다. 프런트엔드에서 호출할 때는 이 token을 함께 전달합니다.

fetch('https://your-worker.workers.dev', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Token': 'your-secret-token',  // 이 token도 프런트엔드 환경 변수에 둘 수 있음
  },
  body: JSON.stringify(data),
});

이 token 역시 프런트엔드에서 볼 수 있지만 최소한 한 단계의 장벽을 추가할 수 있습니다. token을 정기적으로 교체하거나 사용자마다 서로 다른 token을 발급할 수도 있습니다.

IP 허용 목록

애플리케이션을 특정 도메인에서만 사용한다면 출처를 제한할 수 있습니다.

const allowedOrigins = ['https://yourdomain.com', 'http://localhost:3000'];
const origin = request.headers.get('Origin');
if (!allowedOrigins.includes(origin)) {
  return new Response('Forbidden', { status: 403 });
}

여러 API 지원

서로 다른 API를 여러 개 프록시해야 한다면 경로로 구분할 수 있습니다.

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    // 경로에 따라 서로 다른 API로 전달
    if (url.pathname.startsWith('/openai')) {
      return proxyOpenAI(request, env);
    } else if (url.pathname.startsWith('/maps')) {
      return proxyMaps(request, env);
    } else {
      return new Response('Not found', { status: 404 });
    }
  },
};
async function proxyOpenAI(request, env) {
  // OpenAI 프록시 로직
}
async function proxyMaps(request, env) {
  // 지도 API 프록시 로직
}

이렇게 하면 하나의 Worker로 여러 API를 편리하게 처리할 수 있습니다.

OPTIONS 요청 처리(완전한 CORS 지원)

앞의 코드는 POST 요청만 처리합니다. 하지만 브라우저는 교차 출처 요청을 보내기 전에 OPTIONS 프리플라이트 요청을 먼저 보냅니다. 완전한 CORS 처리는 다음과 같이 구현합니다.

export default {
  async fetch(request, env) {
    // CORS 프리플라이트 요청 처리
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, X-API-Token',
          'Access-Control-Max-Age': '86400',
        },
      });
    }
    // ... 정상 요청 처리
  },
};

모니터링과 디버깅

Cloudflare 콘솔에서 Worker의 다음 상태를 확인할 수 있습니다.

  • 요청 수
  • 오류율
  • 응답 시간

로그를 실시간으로 확인하려면 wrangler tail 명령을 사용하세요.

wrangler tail

모든 요청 로그가 출력되어 디버깅하기 편합니다. 코드에서 console.log()로 출력한 내용도 함께 표시됩니다.

자주 묻는 질문

무료 한도를 모두 사용하면 어떻게 하나요?

하루 10만 회 요청은 개인 프로젝트에 충분한 양입니다. 제 프로젝트도 몇 달 동안 사용했지만 무료 한도를 넘은 적이 없습니다.

정말 부족하다면 월 5달러인 Workers 유료 플랜으로 1,000만 회 요청을 사용할 수 있습니다. 서버를 구매하는 것보다 훨씬 합리적인 가격입니다.

Workers는 안정적인가요? 갑자기 중단되지는 않나요?

Cloudflare는 세계 최대 CDN 제공업체 중 하나로 인프라가 매우 안정적입니다. 반년 넘게 사용하면서 서비스를 이용할 수 없었던 적은 없었습니다.

공식적으로 99.99% SLA를 보장하므로 직접 구축한 서버보다 문제가 생길 가능성이 훨씬 낮습니다.

자체 도메인을 사용할 수 있나요?

가능합니다. Cloudflare 콘솔에서 사용자 지정 도메인을 연결하고 DNS를 설정하면 됩니다. 전체 과정은 5분이면 끝나며 인증서는 따로 설정할 필요가 없습니다. HTTPS가 자동으로 적용됩니다.

중국 내 접속 속도는 어떤가요?

Cloudflare는 중국에도 노드가 있어 속도가 괜찮습니다. 제가 테스트했을 때 응답 시간은 대체로 100~300ms였고 해외 API를 직접 호출할 때보다 훨씬 빨랐습니다.

다만 중국 환경에 특화된 서비스보다는 확실히 느립니다. 속도가 특히 중요하다면 Alibaba Cloud Function Compute 같은 중국 Serverless 플랫폼을 고려할 수 있지만 설정은 더 복잡합니다.

JavaScript 외의 언어도 지원하나요?

Workers는 현재 주로 JavaScript와 TypeScript를 지원합니다. 다른 언어에 익숙하다면 WebAssembly로 컴파일하는 방법도 고려할 수 있지만 진입 장벽이 높습니다.

API 프록시처럼 간단한 용도라면 JavaScript로 충분합니다.

이 방식은 정말 안전한가요?

응답에 API Key를 담아 프런트엔드로 반환하지 않는 한 안전합니다. Secrets는 암호화되어 저장되므로 콘솔에서도 평문을 볼 수 없습니다.

물론 프록시가 악용되지 않도록 접근 제어도 구현해야 합니다. 앞에서 설명한 token 검증과 IP 허용 목록을 함께 활용할 수 있습니다.

결론

API Key 노출 문제는 오랫동안 저를 괴롭혔습니다. 처음에는 위험을 감수하거나 돈을 들여 서버를 구매하는 방법밖에 없다고 생각했습니다.

Cloudflare Workers를 알게 된 뒤 이렇게 간단히 해결할 수 있다는 것을 깨달았습니다. 5분 배포, 완전 무료, 안전한 API Key 보관, CORS 문제 해결이라는 장점을 모두 갖춘 Workers는 개인 프로젝트에 거의 완벽한 선택입니다.

타사 API를 호출해야 하는 프로젝트를 만들고 있다면 이 방법을 꼭 사용해 보세요. 어렵지 않습니다. 위 절차를 따라 하면 30분 안에는 충분히 끝낼 수 있습니다.

코드를 자세히 작성했으니 그대로 복사한 뒤 필요한 부분만 수정하면 됩니다. 문제가 있으면 Cloudflare 공식 문서를 찾아보거나 댓글을 남겨 주세요. 확인하는 대로 답변하겠습니다.

마지막으로 한 번 더 강조합니다. 배포 후에는 프록시가 악용되지 않도록 접근 제어를 반드시 적용하세요. token 검증을 추가하거나 출처 도메인을 제한하는 것만으로도 간단하면서 효과적으로 보호할 수 있습니다.

지금 Cloudflare 계정을 만들고 직접 시도해 보세요!

Cloudflare Workers로 API 프록시를 구축해 키를 보호하는 전체 절차

API Key 보안 위험을 이해하는 단계부터 5분 만에 Workers를 배포하는 과정까지, 코드 구현과 보안 모범 사례를 함께 설명합니다.

Estimated time: PT5M

  1. 1

    Step 1: API Key 보안 위험과 기존 방식의 문제 이해

    프런트엔드 API Key 보안 문제:
  2. 2

    Step 2: Cloudflare Workers 방식의 장점 이해

    완전히 무료이면서 성능도 뛰어납니다.
  3. 3

    Step 3: 5분 배포 절차: Wrangler 설치와 Worker 생성

    1단계: Wrangler CLI 설치
  4. 4

    Step 4: 핵심 코드로 API 프록시 구현

    핵심 코드의 흐름은 프런트엔드 요청 수신→환경 변수에서 API Key 읽기→대상 API로 요청 전달→요청 헤더에 API Key 추가→프런트엔드로 응답 반환입니다. GET/POST 등 모든 HTTP 메서드를 지원할 수 있습니다. 코드 예: export default { async fetch(request, env) { const url = new URL(request.url); const targetUrl = url.searchParams.get(‘url’); if (!targetUrl) { return new Response(‘Missing url parameter’, { status: 400 }); } const apiKey = env.OPENAI_API_KEY; const response = await fetch(targetUrl, { method: request.method, headers: { ‘Authorization’: Bearer ${apiKey}, ‘Content-Type’: ‘application/json’ }, body: request.method !== ‘GET’ ? await request.text() : undefined }); return new Response(response.body, { headers: { ‘Access-Control-Allow-Origin’: ’*’, ‘Access-Control-Allow-Methods’: ‘GET, POST, PUT, DELETE, OPTIONS’, ‘Access-Control-Allow-Headers’: ‘Content-Type’ } }); } }. 이 코드는 1) URL 매개변수에서 대상 API 주소를 가져오고, 2) 환경 변수에서 API Key를 읽고, 3) 요청 헤더에 API Key를 추가해 대상 API로 요청을 전달하고, 4) 응답에 CORS 헤더를 설정해 프런트엔드로 반환합니다.
  5. 5

    Step 5: 배포 및 프런트엔드 호출

    코드 배포: 프로젝트 디렉터리에서 wrangler deploy를 실행하면 Wrangler가 Worker를 Cloudflare에 자동으로 배포합니다. 배포에 성공하면 your-worker-name.your-subdomain.workers.dev 형식의 URL이 표시됩니다. 프런트엔드 호출: 기존의 직접 API 호출 코드를 Worker 주소 호출로 바꿉니다. 예를 들어 기존 코드는 fetch(‘https://api.openai.com/v1/chat/completions’, { headers: { ‘Authorization’: ‘Bearer YOUR_API_KEY’ } })입니다. 이를 fetch(‘https://your-worker-name.your-subdomain.workers.dev?url=https://api.openai.com/v1/chat/completions’)로 바꿉니다. 그러면 API Key가 서버 측에 안전하게 보관되어 프런트엔드에는 전혀 노출되지 않습니다. 모니터링과 디버깅: Cloudflare 콘솔에서 Worker의 요청 수, 오류율, 응답 시간을 확인할 수 있습니다. wrangler tail 명령을 사용하면 모든 요청 로그가 실시간으로 출력되어 디버깅하기 편하며, 코드에서 console.log()로 출력한 내용도 함께 표시됩니다.
  6. 6

    Step 6: 보안 모범 사례와 자주 묻는 질문

    보안 모범 사례: 1) API Key를 하드코딩하지 말고 환경 변수에 보관합니다. wrangler secret put 명령으로 설정하면 Secrets가 암호화되어 저장됩니다. 2) Cloudflare Rate Limiting 기능 등으로 요청 속도를 제한해 악용을 방지합니다. 3) Referer 또는 CORS로 요청 출처를 검증하고 특정 도메인만 허용합니다. 4) wrangler tail로 접근 로그를 확인해 이상 징후를 모니터링합니다. 5) 이상한 접근이 발견되면 API Key를 즉시 교체하고 정기적으로 순환합니다. 자주 묻는 질문: 무료 한도를 모두 사용하면 어떻게 하나요? 하루 10만 회 요청은 개인 프로젝트에 충분합니다. 정말 부족하다면 월 5달러인 Workers 유료 플랜으로 1,000만 회 요청을 사용할 수 있습니다. Workers는 안정적인가요? Cloudflare는 세계 최대 CDN 제공업체 중 하나로 인프라가 매우 안정적이며 공식적으로 99.99% SLA를 보장합니다. 자체 도메인을 사용할 수 있나요? Cloudflare 콘솔에서 사용자 지정 도메인을 연결하고 DNS를 설정하면 됩니다. 전체 과정은 5분이면 끝나며 HTTPS가 자동으로 적용됩니다. 중국 내 접속 속도는 어떤가요? Cloudflare는 중국에도 노드가 있어 응답 시간은 일반적으로 100~300ms이며 해외 API를 직접 호출할 때보다 훨씬 빠릅니다. 이 방식은 정말 안전한가요? 응답에 API Key를 담아 프런트엔드로 반환하지 않는 한 안전합니다. Secrets는 암호화되어 저장되므로 콘솔에서도 평문을 볼 수 없습니다. 물론 프록시가 악용되지 않도록 접근 제어도 구현해야 합니다.

FAQ

프런트엔드의 API Key는 왜 안전하지 않으며, 어떻게 도용되나요?
프런트엔드 코드는 완전히 공개됩니다.
• 많은 사람이 .env 파일이나 Vite의 import.meta.env를 사용하면 안전하다고 생각하지만, 이는 개발 편의를 위한 도구일 뿐이며 build 후에는 모든 환경 변수가 JS 파일에 하드코딩됩니다.
• 직접 확인할 수도 있습니다. 아무 프런트엔드 프로젝트의 운영 환경에서 F12로 개발자 도구를 열고 Network 패널로 이동한 뒤 페이지를 새로 고치면 요청 헤더, 요청 본문, URL 매개변수를 비롯한 모든 API 요청이 노출됩니다.
• 코드를 난독화하거나 압축해도 읽기만 조금 어려워질 뿐입니다. API를 호출할 때는 실제 Key를 전송해야 하므로 이를 난독화할 수 없습니다.
• 암호화를 생각할 수도 있지만 암호화와 복호화 코드가 모두 프런트엔드에 있으므로 사용자가 똑같이 볼 수 있습니다.
• 결국 프런트엔드는 사용자의 브라우저에서 실행됩니다. 개발자가 할 수 있는 일은 사용자도 할 수 있으므로 근본적으로 해결할 수 없습니다.

도용으로 인한 비용:
• GitHub에는 프로젝트를 자동으로 스캔해 코드에 노출된 API Key를 찾는 도구가 있습니다.
• Key를 발견한 사람은 무료 혜택을 악용하거나 다른 사람에게 판매하려고 API를 마구 호출할 수 있습니다.
• OpenAI API는 token 단위로 과금되므로 하룻밤 사이 수백 위안이 청구되는 일이 흔하고, 심하면 수천 위안까지 나올 수 있습니다.
• 누군가 AI 채팅 페이지의 Key를 프런트엔드에 넣었다가 도용당해 무단 호출이 이어졌고, 한 달 청구액이 2,000달러를 넘은 사례도 있습니다.
• OpenAI뿐 아니라 Google Maps API, 각종 날씨 API와 번역 API처럼 사용량 기반으로 과금되는 서비스는 모두 도용 위험이 있습니다.
Cloudflare Workers 방식의 장점은 무엇이며, 왜 이 서비스를 선택하나요?
완전히 무료이면서 성능도 뛰어납니다.
• Cloudflare Workers의 무료 한도는 하루 10만 회 요청입니다.
• 개인 프로젝트에는 충분한 양입니다. 제가 만든 작은 도구도 하루 호출이 수백 회뿐이라 무료 한도로 넉넉합니다.
• 전 세계 200개 이상의 노드에서 사용자를 가장 가까운 노드로 자동 라우팅하므로 지연 시간이 매우 낮고, 응답 시간은 일반적으로 100~300ms입니다.

API Key를 서버 측 환경 변수에 안전하게 보관합니다.
• Secrets는 암호화되어 저장되므로 콘솔에서도 평문을 볼 수 없고 프런트엔드에는 전혀 노출되지 않습니다.
• CORS도 처리할 수 있어 별도 교차 출처 설정이 필요 없습니다.

5분이면 간단히 배포할 수 있습니다.
• 자체 서버처럼 환경을 설정하고 SSL 인증서와 CORS를 처리할 필요가 없어 Workers 배포가 훨씬 간단합니다.

기존 방식의 문제:
• 비용: 가장 저렴한 클라우드 서버도 매달 50~100위안이 들어 개인 프로젝트에는 부담스럽습니다.
• 복잡한 설정: Node.js 설치, Nginx 설정, SSL 인증서 발급, CORS 설정에 반나절이 걸릴 수 있습니다.
• 유지 관리 비용: 서버를 주기적으로 업데이트하고 상태를 모니터링해야 하며, 장애가 나면 재시작해야 합니다. 작은 프로젝트에는 지나친 부담입니다.
Cloudflare Workers로 API 프록시를 만드는 구체적인 절차는 무엇인가요?
5분 배포 절차:

1단계: Wrangler CLI를 설치합니다. 터미널에서 npm install -g wrangler를 실행하고 wrangler --version으로 설치를 확인합니다.
2단계: Cloudflare에 로그인합니다. 터미널에서 wrangler login을 실행하면 인증할 브라우저가 자동으로 열립니다.
3단계: Worker 프로젝트를 만듭니다. mkdir api-proxy, cd api-proxy, wrangler init을 차례로 실행합니다.
4단계: API Key를 보관할 환경 변수를 설정합니다. wrangler secret put OPENAI_API_KEY를 실행한 뒤 API Key를 입력하면 서버에 안전하게 저장되어 프런트엔드에는 노출되지 않습니다.

핵심 코드 작성:
• 프런트엔드 요청 수신→환경 변수에서 API Key 읽기→대상 API로 요청 전달→요청 헤더에 API Key 추가→응답 반환
• GET/POST 등 모든 HTTP 메서드를 지원할 수 있습니다.
• 코드는 URL 매개변수에서 대상 API 주소를 가져오고 환경 변수에서 API Key를 읽어 요청 헤더에 추가한 뒤, 응답에 CORS 헤더를 설정해 프런트엔드로 반환합니다.

코드 배포:
• 프로젝트 디렉터리에서 wrangler deploy를 실행하면 Wrangler가 Worker를 Cloudflare에 자동으로 배포합니다.
• 배포에 성공하면 your-worker-name.your-subdomain.workers.dev 형식의 URL이 표시됩니다.

프런트엔드 호출: 기존의 직접 API 호출 코드를 Worker 주소 호출로 바꾸면 API Key가 서버 측에 안전하게 보관되어 프런트엔드에는 전혀 노출되지 않습니다.
Workers 무료 한도로 충분한가요? 한도를 모두 사용하면 어떻게 하나요?
무료 한도:
• Cloudflare Workers의 무료 한도는 하루 10만 회 요청입니다.
• 개인 프로젝트에는 충분한 양입니다. 제가 만든 작은 도구도 하루 호출이 수백 회뿐이라 무료 한도로 넉넉합니다.
• 제 프로젝트는 몇 달 동안 사용했지만 무료 한도를 넘은 적이 없습니다.
• 정말 부족하다면 월 5달러인 Workers 유료 플랜으로 1,000만 회 요청을 사용할 수 있습니다.
• 서버를 구매하는 것보다 훨씬 합리적인 가격입니다.

모니터링과 디버깅:
• Cloudflare 콘솔에서 Worker의 요청 수, 오류율, 응답 시간을 확인할 수 있습니다.
• wrangler tail 명령을 사용하면 모든 요청 로그가 실시간으로 출력되어 디버깅하기 편합니다.
• 코드에서 console.log()로 출력한 내용도 함께 표시됩니다.
Workers는 안정적인가요? 자체 도메인을 사용할 수 있나요? 중국 내 접속 속도는 어떤가요?
안정성:
• Cloudflare는 세계 최대 CDN 제공업체 중 하나로 인프라가 매우 안정적입니다.
• 반년 넘게 사용하면서 서비스를 이용할 수 없었던 적은 없었습니다.
• 공식적으로 99.99% SLA를 보장하므로 직접 구축한 서버보다 문제가 생길 가능성이 훨씬 낮습니다.

사용자 지정 도메인:
• 사용할 수 있습니다. Cloudflare 콘솔에서 사용자 지정 도메인을 연결하고 DNS를 설정하면 됩니다.
• 전체 과정은 5분이면 끝나며 인증서는 따로 설정할 필요가 없습니다. HTTPS가 자동으로 적용됩니다.

중국 내 접속 속도:
• Cloudflare는 중국에도 노드가 있어 속도가 괜찮습니다.
• 제가 테스트했을 때 응답 시간은 대체로 100~300ms였고 해외 API를 직접 호출할 때보다 훨씬 빨랐습니다.
• 다만 중국 환경에 특화된 서비스보다는 확실히 느립니다.
• 속도가 특히 중요하다면 Alibaba Cloud Function Compute 같은 중국 Serverless 플랫폼을 고려할 수 있지만 설정은 더 복잡합니다.
이 방식은 정말 안전한가요? 어떤 보안 모범 사례를 따라야 하나요?
보안:
• 응답에 API Key를 담아 프런트엔드로 반환하지 않는 한 안전합니다.
• Secrets는 암호화되어 저장되므로 콘솔에서도 평문을 볼 수 없습니다.
• 물론 프록시가 악용되지 않도록 접근 제어도 구현해야 합니다.

보안 모범 사례:
1) API Key를 하드코딩하지 말고 환경 변수에 보관합니다. wrangler secret put 명령으로 설정하면 Secrets가 암호화되어 저장됩니다.
2) Cloudflare Rate Limiting 기능 등으로 요청 속도를 제한해 악용을 방지합니다.
3) Referer 또는 CORS로 요청 출처를 검증하고 특정 도메인만 허용합니다.
4) wrangler tail로 접근 로그를 확인해 이상 징후를 모니터링합니다.
5) 이상한 접근이 발견되면 API Key를 즉시 교체하고 정기적으로 순환합니다.

token 검증을 추가하거나 출처 도메인을 제한하는 것만으로도 간단하면서 효과적으로 보호할 수 있습니다. 배포 후에는 접근 제어를 적용해 프록시가 악용되지 않게 하세요.

4분 읽기 · 게시일: 2025년 12월 1일 · 수정일: 2026년 9월 8일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog