Software Design

[바이브 코더 #2] API가 뭐길래, API 키는 왜 숨기라는 걸까

지난 1편에서 앱을 식당에 비유했습니다. 홀(프론트엔드), 주방(백엔드), 창고(DB). 이번에는 그 구조 위에서 바이브 코딩 사고가 가장 잦은 주제를 다룹니다. API, 그리고 API 키입니다. "키를 절대 노출하지 마세요"라는 경고는 다들 한 번쯤 봤을 텐데, 정작 그 키가…

이석우iOS Developer6분 읽기
[바이브 코더 #2] API가 뭐길래, API 키는 왜 숨기라는 걸까 대표 이미지
API KEY WHY YOU MUST HIDE IT 텍스트와 함께 API 주문 창구에 API KEY 법인카드를 넣는 손과 이를 노리는 검은 손을 그린 히어로 이미지
API 키는 법인카드입니다. 누가 긁든 청구서는 나에게 옵니다

지난 1편에서 앱을 식당에 비유했습니다. 홀(프론트엔드), 주방(백엔드), 창고(DB). 이번에는 그 구조 위에서 바이브 코딩 사고가 가장 잦은 주제를 다룹니다. API, 그리고 API 키입니다. “키를 절대 노출하지 마세요”라는 경고는 다들 한 번쯤 봤을 텐데, 정작 그 키가 뭐고 어디에 있으며 노출되면 무슨 일이 벌어지는지 짚어주는 곳은 드뭅니다. 이번 글에서 한 번에 정리합니다.

API는 주문 창구입니다

API는 Application Programming Interface의 약자인데, 약자 풀이는 잊어도 됩니다. 핵심은 이것입니다. API는 프로그램끼리 일을 시키는 주문 창구입니다.

식당 비유로 돌아가면, 손님은 주방에 들어갈 수 없습니다. 대신 주문 창구에 정해진 양식으로 주문서를 넣습니다. “김치찌개 1개, 덜 맵게.” 그러면 주방이 알아서 만들어 내보내죠. API가 정확히 이 창구입니다. 정해진 주소로 정해진 형식의 요청을 보내면 정해진 형식의 응답이 돌아옵니다.

바이브 코더의 앱에는 API가 두 방향으로 존재합니다.

  • 내 앱의 API: 내 프론트엔드가 내 백엔드에 일을 시키는 창구입니다. 1편에서 본 app/api/ 폴더가 바로 이것입니다.
  • 남의 API: 내 앱이 다른 회사의 서비스에 일을 시키는 창구입니다. ChatGPT에게 글을 시키고(OpenAI API), 지도를 띄우고(지도 API), 결제를 처리하는(결제 API) 것이 전부 남의 창구에 주문서를 넣는 일입니다.

바이브 코딩으로 만드는 앱은 대부분 이 “남의 API”를 조합해서 굴러갑니다. 그리고 남의 창구에 주문을 넣으려면 반드시 필요한 것이 하나 있습니다.

FRONTEND MY BACKEND EXTERNAL API 사이 요청 흐름에서 API KEY는 .env와 배포 대시보드에만 두고 프론트엔드에는 절대 두지 않는 구조 다이어그램
키가 다닐 수 있는 길은 백엔드에서 외부 API로 가는 길 하나뿐입니다

API 키는 법인카드입니다

남의 API는 공짜 창구가 아닙니다. OpenAI에 요청을 한 번 보낼 때마다 비용이 발생하죠. 그래서 모든 요청에는 “이 주문의 청구서를 누구에게 보낼까”를 밝히는 신분증이 붙습니다. 그게 API 키입니다. sk-proj-...처럼 생긴 길고 무작위한 문자열이요.

API 키의 성질은 법인카드와 똑같습니다.

  • 카드를 긁는 사람이 누구든, 청구서는 카드 주인에게 갑니다.
  • 카드번호만 알면 쓸 수 있습니다. 얼굴 확인도, 서명 확인도 없습니다.
  • 그래서 카드번호를 공개된 곳에 적어두면, 전 세계 누구나 내 돈으로 결제할 수 있게 됩니다.

“키를 숨기라”는 경고가 이렇게 무거운 이유입니다. 키 노출은 비밀번호 노출과 다릅니다. 비밀번호는 바꾸면 그만이지만, 키는 도용당한 시점부터 재발급까지 쓴 요금이 전부 내 청구서에 쌓입니다.

노출되면 실제로 벌어지는 일

“에이, 내 작은 앱의 키를 누가 찾아내겠어”라고 생각하기 쉬운데, 여기가 가장 위험한 착각입니다. 키를 찾는 것은 사람이 아니라 입니다.

BOTS FIND LEAKED KEYS IN MINUTES 문구와 함께 공개 코드 저장소를 훑는 로봇들이 sk- 키를 찾아내는 장면의 일러스트
키를 찾아내는 건 사람이 아니라 24시간 도는 봇입니다

GitHub 같은 공개 코드 저장소는 봇 수천 개가 24시간 새 코드를 훑고 있습니다. 실수로 키가 포함된 코드를 공개 저장소에 올리면, 보통 몇 분 안에 봇이 수집해갑니다. 수집된 키는 곧바로 무료 AI 호출, 암호화폐 채굴 결제, 스팸 발송 같은 데 쓰입니다. 하룻밤 사이에 수백만 원이 청구됐다는 사고 사례가 커뮤니티에 꾸준히 올라오는 이유입니다.

또 하나의 노출 경로는 1편에서 다룬 그것입니다. 프론트엔드에 키를 넣는 것. 프론트엔드 코드는 사용자 브라우저로 전송되므로, 마우스 오른쪽 버튼 “검사” 한 번이면 누구나 키를 꺼낼 수 있습니다. AI에게 “OpenAI 연동해줘”라고 시켰을 때 AI가 편의상 키를 프론트엔드에 박아버리는 경우가 실제로 있어서, 반드시 직접 확인해야 합니다.

키가 있어야 할 자리

원칙은 1편에서 이미 나왔습니다. 비밀은 백엔드에. 구체적으로는 이렇습니다.

  • 키는 프로젝트의 .env 파일에 적습니다. 백엔드만 읽는 비밀 값 보관함입니다.
  • .env 파일은 .gitignore라는 목록에 등록해서 Git이 따라가지 않게 합니다. 그래야 GitHub에 코드를 올려도 키는 내 컴퓨터에만 남습니다. AI가 만들어준 프로젝트는 보통 등록돼 있지만, 한 번은 직접 확인할 가치가 있습니다.
  • 배포한 앱은 내 컴퓨터의 .env를 못 읽으므로, Vercel 같은 배포 서비스의 대시보드에 있는 “Environment Variables” 메뉴에 키를 따로 등록합니다. 이 이야기는 4편(배포)에서 다시 나옵니다.

Next.js에는 함정이 하나 더 있습니다. 환경변수 이름이 NEXT_PUBLIC_으로 시작하면, 그 값은 프론트엔드까지 전송됩니다. 이름 그대로 public, 공개된다는 뜻입니다. 지도 표시용 키처럼 공개해도 되도록 설계된 키만 여기에 두고, 요금이 나가는 키(OpenAI 등)에는 절대 NEXT_PUBLIC_을 붙이면 안 됩니다. AI가 붙여놨다면 그 자체가 위험 신호입니다.

내 앱 셀프 점검법

지금 바로 확인할 수 있는 3가지입니다.

  1. 브라우저 검사: 배포된 내 사이트에서 마우스 오른쪽 버튼 → 검사 → 상단 Network 또는 Sources 탭에서 sk-, key, secret 같은 단어를 검색해봅니다. 내 비밀 키가 검색되면 노출된 것입니다.
  2. GitHub 검사: 내 저장소가 공개(Public) 상태라면, 저장소 검색창에 키 앞부분을 검색해봅니다. 과거 커밋에 남아 있어도 노출입니다.
  3. AI에게 감사 요청: “이 프로젝트에서 API 키나 비밀 값이 프론트엔드로 전송되는 곳이 있는지 전부 찾아줘”라고 시킵니다. 만들 때 실수한 AI도 찾을 때는 잘 찾습니다.

이미 노출됐다면

노출된 키는 숨겨도 소용없습니다. 봇이 이미 복사해갔다고 가정해야 합니다. 순서는 이렇습니다.

  1. 해당 서비스 대시보드에서 그 키를 삭제(폐기) 합니다. 이 순간부터 도용이 멈춥니다.
  2. 새 키를 발급받아 이번에는 .env와 배포 대시보드에만 넣습니다.
  3. 서비스의 사용량 한도(spending limit) 를 설정합니다. 다음 사고 때 피해 상한선이 됩니다. 이 이야기는 7편(요금 폭탄)에서 자세히 다룹니다.

정리

  • API는 프로그램끼리의 주문 창구이고, 내 앱은 남의 API를 조합해 굴러갑니다.
  • API 키는 법인카드입니다. 누가 쓰든 청구서는 나에게 옵니다.
  • 키는 봇이 몇 분 안에 찾아냅니다. “내 앱은 작으니까”는 방어가 되지 못합니다.
  • 키의 자리는 .env(로컬)와 배포 대시보드의 환경변수, 딱 두 곳입니다. NEXT_PUBLIC_이 붙은 요금 키는 위험 신호입니다.
  • 노출됐다면 숨기지 말고 폐기 → 재발급 → 한도 설정 순서로 대응합니다.

다음 편은 Git입니다. AI가 코드를 다 만들어주는데 왜 다들 Git을 쓰라고 하는지, 그리고 AI가 멀쩡한 앱을 망쳐놨을 때 1분 만에 되돌리는 법을 다룹니다.