C
보안/API보안/Lesson 04

입력 검증 + API 보안 — Rate Limiting · CORS · 환경변수

45분·theory

입력 검증 + API 보안 — Rate Limiting · CORS · 환경변수

🎯 이 lesson 을 읽고 나면

이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.

  • ✅ .env 관리 + GitHub Secret Scanning
  • ✅ API Rate Limit (Token Bucket) 구현
  • ✅ CORS 화이트리스트 + helmet 보안 헤더

학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.

.env 파일 관리 — *GitHub leak 1위 사고 원인*

비밀 정보를 코드에 직접 박지 마세요

javascript
// ❌ 절대 금지
const dbPassword = 'mysecret123';
const awsKey = 'AKIA...';

Git 에 올리면 영구 기록. 누군가 발견하면 즉시 악용.

.env 파일로 분리

bash
# .env
DATABASE_URL=postgresql://user:pass@localhost/db
JWT_SECRET=super_secret_random_string
AWS_ACCESS_KEY=AKIA...
AWS_SECRET_KEY=...
OPENAI_API_KEY=sk-...
javascript
// 코드에서 참조
const db = process.env.DATABASE_URL;
const secret = process.env.JWT_SECRET;

.gitignore 에 반드시

code
# .gitignore
.env
.env.local
.env.production
*.pem
*.key

프로젝트 처음 만들 때 즉시 추가. 한 번 커밋되면 git filter-repo 같은 도구로 history 통째로 다시 쓰는 대공사 필요.

.env.example 은 OK

bash
# .env.example — 실제 값 없이 키 이름만
DATABASE_URL=
JWT_SECRET=
AWS_ACCESS_KEY=

다른 개발자에게 "이 키들이 필요해" 안내용. 실제 값은 없으니 커밋 OK.

GitHub leak 사고 — 실제 사례

  • AWS 키 노출 → 24시간 내에 자동 봇이 발견 → 비트코인 채굴 → 천만 원 청구
  • Stripe 키 노출 → 결제 시스템 탈취
  • OpenAI 키 노출 → 토큰 무한 사용

GitHub Secret Scanning 이 자동 감지하지만 돈은 이미 빠져나간 뒤.

키가 노출됐다면

1. 즉시 키 폐기 (rotate) — AWS/OpenAI 콘솔에서 새 키 발급, 옛 키 삭제
2. Git history 정리git filter-repo 또는 BFG Repo-Cleaner
3. 비용 모니터링 — 청구서 확인
4. 팀에 알림

"한번 노출 = 영구 노출" — 새 키 발급이 필수.

환경별 분리

code
.env.local           # 로컬 개발
.env.development     # 개발 서버
.env.production      # 운영 서버

프로덕션 값은 GitHub Actions Secrets, AWS Parameter Store, Vault 같은 전문 저장소. 절대 .env 파일 로 서버에 두지 마세요 (백업·로그·실수로 노출 위험).

🤖 AI 에게 이렇게 요청해보세요

  • "이 코드에서 하드코딩된 API 키를 process.env 로 빼주고 .env.example 도 만들어줘"
  • "이 프로젝트 .gitignore 가 안전한지 검토해줘"

CORS · Rate Limiting · HTTPS — 3대 방어선

CORS — 왜 브라우저가 차단하나

CORS (Cross-Origin Resource Sharing) 는 브라우저의 안전장치. 다른 도메인의 API 호출을 기본 차단.

code
프론트: https://app.example.com
API:    https://api.other.com
→ 브라우저가 차단 (CORS error)

없으면 — 악성 사이트가 내 은행 사이트의 API 를 내 로그인 쿠키로 호출 가능.

서버에서 허용하기

Express (Node.js)

javascript
import cors from 'cors';

app.use(cors({
    origin: ['https://app.example.com'],   // 허용할 origin 명시
    credentials: true,                       // 쿠키 포함 요청 허용
    methods: ['GET', 'POST', 'PUT', 'DELETE']
}));

Spring Boot

java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("https://app.example.com")
            .allowedMethods("*")
            .allowCredentials(true);
    }
}

안티패턴 — 모든 origin 허용

javascript
app.use(cors({ origin: '*' }));   // ❌ 보안 최악

공개 API 가 아니면 origin 을 화이트리스트 로 명시.

Rate Limiting — 남용 방지

왜 필요한가

  • 공격자가 1초에 1만 회 호출 → 서버 다운
  • 비밀번호 무차별 대입 (brute force)
  • AI API 비용 폭발

Express + express-rate-limit

javascript
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000,    // 15분
    max: 100,                     // IP 당 100회
    message: '요청이 너무 많습니다'
});

app.use('/api/', limiter);

Redis 기반 (분산 환경)

javascript
import { rateLimit } from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';

const limiter = rateLimit({
    store: new RedisStore({ /* ... */ }),
    windowMs: 60_000,
    max: 10
});

서버 인스턴스 여러 대 일 때 Redis 공유. 단일 서버 메모리 카운트는 분산에 부적합.

로그인 엔드포인트는 더 엄격하게

javascript
const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 5,           // 15분에 5회
    skipSuccessfulRequests: true   // 성공한 요청은 카운트 X
});

app.post('/auth/login', loginLimiter, loginHandler);

HTTPS — 2026년 필수

왜 필수인가

  • HTTP 는 평문 전송 — 와이파이 도청 가능
  • Chrome / Safari 가 "안전하지 않음" 표시 → 신뢰도 추락
  • Service Worker · 카메라 등 모던 API 가 HTTPS 강제

Let's Encrypt 무료 인증서

bash
# Nginx + Certbot
sudo certbot --nginx -d example.com -d www.example.com

90일 유효 + 자동 갱신. 0원으로 모든 사이트가 HTTPS.

Vercel · Netlify

자동으로 HTTPS 적용. 별도 설정 0개.

보안 헤더 5가지 — 무료 점수

javascript
// Express helmet 미들웨어 한 줄로 끝
import helmet from 'helmet';
app.use(helmet());

helmet 이 자동 설정:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN (clickjacking 방지)
  • Strict-Transport-Security (HSTS — HTTPS 강제)
  • X-XSS-Protection (옛 브라우저용)
  • Referrer-Policy: strict-origin-when-cross-origin

🤖 AI 에게 이렇게 요청해보세요

  • "이 Express API 에 helmet + CORS 화이트리스트 + 글로벌 rate limit 추가해줘"
  • "로그인 엔드포인트에 5분에 5회 제한 추가해줘"
  • "이 코드의 보안 취약점 5가지를 찾아줘"
다음 추천: DevOps
입력 검증 + API 보안 — Rate Limiting · CORS · 환경변수 - 보안