솔로 개발자를 위한 “Just Enough” API 보안 설계

발행: (2025년 12월 29일 오전 11:13 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

완벽을 추구하지 마세요.
API를 여러 층으로 보호하세요.

왜 API 보안이 혼자 개발자에게 어려운가

  • 무한한 공격 표면: 보안을 생각하기 시작하면 가능한 공격 목록이 끝없이 늘어납니다.
  • 불안 루프: “이 공격이 발생하면 어떨까?” → “그 상황은 어떨까?” → 앞으로 나아가기 어려워짐.
  • 제한된 자원: 방어 수단을 제한된 수만 관리할 수 있으므로 명확한 경계가 필요합니다.

범위 정의

구현하기 전에 스스로에게 물었다:

  • 내가 고려할 것 – 방어해야 할 위협.
  • 내가 의도적으로 무시할 것 – 단독 프로젝트 범위를 벗어난 공격.

이것은 정식 위협 모델이 아니었으며, API를 구축하면서 점진적으로 발전했다.

보호해야 할 것

  • 인증되지 않은 요청
  • 잘못되었거나 형식이 틀린 매개변수
  • 도난당했거나 재생된 JWT를 포함한 요청

무시할 것

  • 클라이언트 측 코드의 완전한 비밀 유지
  • 네이티브 앱의 완전한 역공학에 대한 방어
  • API 레이어만으로 모든 가능한 공격을 차단하는 것

계층형 보안 접근 방식

I split responsibilities across three layers. No single layer is trusted completely.

레이어 1 – 클라이언트

  • JWT for user authentication
  • Signature (HMAC) for application identification

레이어 2 – API (Cloudflare Workers + Hono)

  • Application validation (request signing)
  • JWT verification and user identification
  • Basic request validation (method, path, parameters)
  • Lightweight rate limiting

레이어 3 – 데이터베이스 (Supabase)

  • Row‑level security (RLS) to enforce per‑user data isolation

Rule: even if the API is bypassed, other users’ data must never be accessible. Supabase RLS enforces this at the database level.

Application‑level verification

호출 애플리케이션을 검증하기 위해 요청 서명(HMAC)을 사용하지만 고의적으로 다음을 피합니다:

  • 요청 본문 서명
  • 엄격한 논스 관리
  • 완벽한 재전송 방지

대신 다음만 서명합니다:

  • timestamp
  • HTTP method
  • Request path

이 트레이드‑오프는 구현 비용, 운영 복잡성, 실제 위협 수준 사이의 균형을 맞춥니다. 비밀 키가 클라이언트(React Native)에 존재하므로, 단독 개발 환경에서 전체 HMAC‑레벨의 엄격함은 현실적이지 않습니다.

Related article: Protecting the API Entry Point with Cloudflare Workers

로깅 및 가시성

  • 모든 요청은 고유한 requestId를 받습니다.
  • 로그는 구조화된 JSON 형태이며, 집계에 바로 사용할 수 있습니다.
  • 클라이언트에 반환되는 오류 응답은 최소화하고, 내부 로그에서는 인증 실패와 인가 실패를 명확히 구분합니다.
  • 데모에서는 로그가 콘솔에 출력되지만, 프로덕션 수준 로거로 출력 대상을 교체하는 것은 간단합니다.

단계별 설계 프로세스

제가 가장 효과적이라고 생각한 순서:

  1. 가정 수정 – 클라이언트와 사용자를 정의합니다.
  2. 위협 경계 결정 – 보호해야 할 것과 무시해도 되는 것을 구분합니다.
  3. 데이터베이스 잠금 – 교차 사용자 접근을 방지하기 위해 RLS를 활성화합니다.
  4. 사용자 신원 확인 – JWT 인증을 구현합니다.
  5. API 진입점에서 요청 검증 – 기본 검증을 수행하고 예상치 못한 트래픽을 차단합니다.
  6. 필요 시 애플리케이션 수준 식별 추가 – 서명 / 타임스탬프.
  7. 원치 않는 요청 폭주 억제 – 속도 제한(rate limiting).
  8. 문제 추적 가능하게 만들기requestId와 구조화된 로그.

이 순서를 따르니 과도하게 설계되지 않으면서도 실수로 깨지기 어려운 API 설계가 완성되었습니다.

데모 저장소

전체 데모는 다음에서 확인할 수 있습니다:

관련 기사: Supabase와 행 수준 보안(RLS)을 설계한 방법

Conclusion

보안을 처음부터 “올바르게” 설계하는 것은 매우 어렵습니다, 특히 혼자 작업할 때는 더욱 그렇습니다. 다음과 같이 하면:

  • 명확한 경계를 설정하고,
  • 방어를 계층화하며, 그리고
  • 가시성을 일류 고려사항으로 만들면,

복잡함에 빠지지 않고 “충분히” 보안을 달성할 수 있습니다. 이 글이 여러분이 자신의 API 보안을 어느 정도까지 할지 결정하는 데 도움이 되길 바랍니다.

Back to Blog

관련 글

더 보기 »