TuBrief
구독 채널
비디오
커뮤니티

v0로 만든 프로토타입을 기업 DB에 바로 붙이면 안 되는 이유와 안전한 연결법

TuBrief 편집팀
2026년 7월 23일
0
컴퓨터/소프트웨어

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

한국어EnglishEspañol中文العربيةहिन्दीDeutschFrançaisPortuguêsРусскийBahasa Indonesia日本語

관련 영상

Ship 26 NYC - SERHANT가 두 번의 기회 없이 AI를 배포한 방법18:10

Ship 26 NYC - SERHANT가 두 번의 기회 없이 AI를 배포한 방법

Vercel

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

v0로 만든 프로토타입을 기업 DB에 바로 붙이면 안 되는 이유와 안전한 연결법

비개발 직원이 v0나 Cursor 같은 바이브 코딩 툴로 사흘 만에 근사한 웹 앱을 만들어옵니다. 대표는 신나서 당장 상용 DB에 붙여서 고객한테 쓰게 하자고 하죠. 이때 개발진이나 CTO는 식은땀이 납니다. AI가 짜준 코드를 열어보면 클라이언트 컴포넌트 한가운데 DB 접속 문자열(DSN)을 그대로 박아두거나, 아무런 검증 없이 SQL 쿼리를 날리는 판국이니까요.

이걸 그대로 운영 서버에 올리면 사고 나는 건 시간문제입니다. OWASP Top 10 for LLM Applications 2025 리포트에서도 AI 생성 코드의 과도한 권한 부여(LLM06)와 입력값 미검증(LLM05)을 가장 위험한 보안 요소로 짚었습니다. 실제로 웹 애플리케이션 보안 침해 사고의 73%가 입력 검증 부재를 노립니다.

비개발자의 생산성을 꺾지 않으면서도 회사 DB를 지키려면, 프로토타입과 DB 사이에 단단한 통제 레이어를 둬야 합니다.

클라이언트의 DB 직접 접근을 끊는 Zod 검증 레이어

가장 먼저 할 일은 비개발자가 만든 앱이 DB를 직접 호출하지 못하도록 길목을 막는 겁니다. Next.js App Router의 서버 라우트 핸들러를 프록시로 두고, 중간에서 Zod 라이브러리로 들어오는 데이터를 실시간으로 검증해야 합니다. TypeScript의 타입 체크는 개발할 때만 작동할 뿐, 실제 유저가 이상한 데이터를 보낼 때 서버가 터지는 걸 막아주지 못합니다.

검증 항목 브라우저 UI 단 검증 서버 사이드 Zod 프록시 레이어
실행 위치 고객 브라우저 Vercel 서버리스 런타임
보안성 개발자 도구로 쉽게 우회 서버에서 강제 차단하여 DB 보호
데이터 검증 형식적인 텍스트 체크 런타임 값 범위 및 타입 정밀 검증
실패 처리 화면에 경고 문구 표시 HTTP 400 반환 및 Sentry 오류 기록

구축 순서는 단순합니다.

  1. 프로젝트 내 app/api/v1/customer-records/route.ts 파일부터 만듭니다.
  2. Zod 스키마를 정의합니다. companyName은 최소 2자 이상, contactEmail은 이메일 양식, employeeCount는 양의 정수만 받도록 규격을 짭니다.
  3. request.json()으로 들어온 요청을 schema.parse()로 검사합니다. 통과한 알맹이만 Prisma ORM으로 DB에 넣고, 실패하면 그 자리에서 400 에러를 뱉고 튕겨냅니다.

앱 단 검증과 함께 DB 자체에도 방어막을 쳐야 합니다. PostgreSQL 기반 Supabase를 쓴다면 Row Level Security(RLS) 설정이 답입니다. 유저 역할 정보를 사용자가 조작할 수 있는 raw_user_meta_data 대신 관리자만 만지는 raw_app_meta_data에 넣어두고 JWT를 검증합니다.

-- 1. 테이블 RLS 활성화
ALTER TABLE public.enterprise_documents ENABLE ROW LEVEL SECURITY;

-- 2. JWT에서 사용자 역할 추출하는 함수 생성
CREATE OR REPLACE FUNCTION get_user_role()
RETURNS text AS $$
  SELECT NULLIF(current_setting('request.jwt.claims', true)::json->'app_metadata'->>'user_role', '');
$$ LANGUAGE sql STABLE;

-- 3. 부서가 같거나 관리자인 경우만 조회 허용하는 정책
CREATE POLICY "Department Access Policy" ON public.enterprise_documents
FOR SELECT USING (
  get_user_role() = 'admin' OR
  department = (current_setting('request.jwt.claims', true)::json->'app_metadata'->>'department')
);

이 작업을 해두면 비개발자가 실수로 서비스 역할 키(Service Role Key)를 코드에 흘려도, 다른 부서의 보안 문서는 절대로 터릴 일이 없습니다.

소스 코드 스캔으로 API 키 유출 막기

AI 툴은 일단 화면을 띄우는 데 집중하도록 설계되어 있어서, API 키나 DB 커넥션 문자열을 브라우저에 노출되는 위치에 막 씁니다. 가장 자주 보이는 실수가 NEXT_PUBLIC_ 접두사를 아무 데나 붙이는 겁니다. Next.js에서 이 접두사가 붙은 변수는 브라우저 JavaScript 파일에 평문으로 들어갑니다. NEXT_PUBLIC_OPENAI_API_KEY 같은 변수를 만드는 순간, F12 개발자 도구를 열 줄 아는 누구든 내 API 키를 가져가서 마음껏 쓸 수 있습니다.

2026년 4월 Vercel 인프라에서 발생한 보안 침해 사고만 봐도 그렇습니다. 연동된 서깃파티 AI 도구의 권한이 뚫리면서 감춰두지 않은 환경 변수들이 노출됐고, 수많은 팀이 밤을 새우며 DB 비밀번호와 API 키를 일일이 재발급해야 했습니다.

이런 실수를 사람이 눈으로 일일이 검수하는 건 불가능합니다. GitHub Actions에 Gitleaks 정적 분석 도구를 붙여서 코드 합치기 전에 자동으로 털어내야 합니다.

name: Security Scan

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  gitleaks-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install and Run Gitleaks
        run: |
          wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz
          tar -xzvf gitleaks_8.18.0_linux_x64.tar.gz
          sudo mv gitleaks /usr/local/bin/
          gitleaks detect --source=. --verbose --redact --exit-code=1

  public-env-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check Unsafe Public Keys
        run: |
          UNSAFE=$(grep -rn "NEXT_PUBLIC_.*\(SECRET\|KEY\|PASSWORD\|TOKEN\|DSN\)" . || true)
          if [ -n "$UNSAFE" ]; then
            echo "클라이언트에 노출된 민감 변수 발견:"
            echo "$UNSAFE"
            exit 1
          fi

이 파이프라인을 세팅해두면 비개발자가 API 키를 소스 코드나 NEXT_PUBLIC_ 변수에 넣고 Push하는 순간 배포가 자동으로 차단됩니다.

Vercel 대시보드에 변수를 등록할 때도 Development, Preview, Production 스코프를 확실히 나눠야 합니다. 특히 Sensitive Environment Variable 체크박스를 반드시 켜두세요. 빌드 로그에 출력되지 않고 대시보드에서도 평문 복사가 안 되게 암호화됩니다.

장애 발생 시 비개발자도 30초 만에 복구하는 방법

OpenAI나 Anthropic 서버가 먹통이 되거나 응답이 늦어지면 서버리스 핸들러 전체가 대기 상태에 빠지면서 연쇄 장애가 납니다. 이럴 때는 Node.js의 opossum 라이브러리로 서킷 브레이커를 걸어줘야 합니다.

import CircuitBreaker from 'opossum';

async function callLLM(prompt: string) {
  // LLM API 호출 로직
}

const options = {
  timeout: 5000, // 5초 넘어가면 실패 처리
  errorThresholdPercentage: 50, // 실패율 50% 넘으면 차단기 오픈
  resetTimeout: 30000 // 30초 후 다시 시도
};

const breaker = new CircuitBreaker(callLLM, options);
breaker.fallback(() => ({ error: "AI 응답이 지연되고 있습니다. 잠시 후 다시 시도해주세요." }));

API 응답이 늦어지면 0.1초 만에 준비된 안내 문구를 보내서 전체 서비스가 다운되는 걸 막을 수 있습니다.

장애 상황을 비개발자 제작자가 바로 알 수 있도록 Sentry와 Slack 웹훅도 연결해둡니다.

// app/api/webhooks/sentry-to-slack/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const event = await request.json();
    const webhookUrl = process.env.SLACK_INCOMING_WEBHOOK_URL;

    if (!webhookUrl) return NextResponse.json({ error: 'Webhook 없음' }, { status: 500 });

    const title = event.data?.issue?.title || '알 수 없는 시스템 오류';
    const issueUrl = event.data?.issue?.permalink || '#';

    await fetch(webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        blocks: [
          {
            type: 'header',
            text: { type: 'plain_text', text: '🚨 프로덕션 오류 발생' }
          },
          {
            type: 'section',
            text: { type: 'mrkdwn', text: `*오류 내용:*\n${title}` }
          },
          {
            type: 'actions',
            elements: [
              {
                type: 'button',
                text: { type: 'plain_text', text: 'Sentry 리포트 보기' },
                url: issueUrl,
                style: 'danger'
              }
            ]
          }
        ]
      })
    });

    return NextResponse.json({ success: true });
  } catch (err) {
    return NextResponse.json({ error: '웹훅 실패' }, { status: 500 });
  }
}

오류가 커져서 메인 페이지가 안 뜨는 P1 등급 장애가 발생하면 개발자를 기다릴 필요도 없습니다. Vercel은 이전 배포본을 그대로 보관하고 있어서 클릭 몇 번으로 직전 상태로 돌릴 수 있습니다.

  1. Slack 채널로 P1 장애 알림을 받습니다.
  2. Vercel 대시보드의 Deployments 탭으로 이동합니다.
  3. 목록에서 바로 아래에 있는 정상 작동했던 배포본(Ready 상태)을 찾습니다.
  4. 우측 점 세 개 버튼(...)을 누르고 Promote to Production을 클릭합니다.

30초만 기다리면 도메인 라우팅이 이전 버전으로 바뀝니다. Zod 검증, Gitleaks 스캔, Vercel 롤백 절차까지 갖춰두면 비개발자가 마음껏 앱을 만들게 두면서도 밤에 다리 뻗고 잘 수 있습니다.