Skip to content

API Routing Conventions

새 endpoint / secret 추가 시 따를 컨벤션. PR #79 (Registry 도입, 2026-05-12) + 봇 리뷰 라운드에서 합의된 룰을 영구화.

Why

ACL Registry 가 helper 자동 선택을 강제하지만 path 선택 / secret 비교 방식 까지는 자동화 X. 명시 안 하면 새 endpoint 추가하는 사람이 옛 패턴 (path-prefix exempt 매트릭스 / 일반 == 비교) 으로 회귀할 위험.

R1 — Audience-based path

endpoint 가 호출되는 청중에 따라 path prefix 결정:

청중path등록 helper
admin (X-Admin-Key) 전용/api/v1/admin/*Admin
사용자 (모바일/웹) 전용/api/v1/* (admin 제외)Authenticated / Anonymous / AuthIssue
시스템 (Google SSV, health probe)/api/v1/admob/ssv, /actuator/*AdMobSSV / Actuator

한 동작을 두 청중이 모두 호출 하면 endpoint 2 개 (각 청중의 path 아래). 같은 핸들러를 두 helper 로 wrap 하지 말고, 핸들러 로직을 서비스 함수로 빼고 각 endpoint 핸들러가 서비스 호출.

예: PR #79 에서 POST /api/v1/disclosures/fetch (JWT 보호 — admin-only 디버깅 endpoint 임) → POST /api/v1/admin/disclosures/fetch 로 이동. 사용자가 호출할 일 없는 endpoint 가 admin path 밖에 있으면 audience contract 가 깨짐.

R2 — Registry helper 강제

mux.Handle / mux.HandleFunc 직접 호출 금지. 모든 라우트는 pkg/route.Registry 의 6 helper 중 하나로 등록:

  • Authenticated — AppCheck + JWT 필수
  • Anonymous — AppCheck (or Worker secret) + JWT 선택. 비로그인 read.
  • AuthIssue — AppCheck + JWT 면제. 토큰 발급 자체.
  • Admin — X-Admin-Key
  • AdMobSSV — ECDSA (핸들러 안)
  • Actuator — 의도된 무 ACL

Registry 우회 (mux 직접 등록) 시 ACL 누락 가능. 카테고리 매트릭스는 docs/spec/backend-structure.md "Route ACL 매트릭스" 참조.

R3 — Secret 비교는 ConstantTimeCompare

X-Admin-Key, X-Worker-Secretsecret 비교는 crypto/subtle.ConstantTimeCompare 사용. 일반 == / != 는 첫 바이트 불일치에서 short-circuit → 타이밍 oracle 로 prefix 노출 가능.

go
import "crypto/subtle"

if subtle.ConstantTimeCompare([]byte(got), []byte(expected)) != 1 {
    w.WriteHeader(http.StatusForbidden)
    return
}

HTTPS + IP rate limit 으로 실제 exploit 난이도는 높지만, secret 비교는 cost-free 한 줄 교체이므로 일관 적용.

R4 — RateLimit 우선순위

Authenticated / Admin chain 에서 rate limit 미들웨어가 인증 검증 (RequireAuth / RequireAdminKey) 보다 바깥:

go
// 올바름
appCheckMW(generalRLMW(requireAuthMW(next)))
generalRLMW(requireAdminKeyMW(next))

// 잘못됨 — 인증 실패 요청이 RL 토큰 소비 없이 차단
appCheckMW(requireAuthMW(generalRLMW(next)))
requireAdminKeyMW(generalRLMW(next))

인증 검증이 바깥이면 무인증/잘못된 키 요청은 RL 소비 없이 즉시 401/403 → 방어 심도 손실 (브루트포스 시도가 RL 카운터에 안 잡힘, soft AppCheck 모드에선 무인증 플러딩 가능).

적용 시점

  • 새 endpoint 핸들러 작성 시 → R1, R2 검토
  • 새 secret 환경변수 추가 + 검증 미들웨어 작성 시 → R3 적용
  • Registry helper 추가 (7번째 카테고리 신설) 시 → R4 패턴 따라 chain 합성

참조