feat(security): API 키 보호, CORS 강화, Rate Limiting KV 전환

보안 개선:
- API 키 하드코딩 제거 (NAMECHEAP_API_KEY_INTERNAL)
- CORS 정책: * → hosting.anvil.it.com 제한
- /health 엔드포인트 DB 정보 노출 방지
- Rate Limiting 인메모리 Map → Cloudflare KV 전환
  - 분산 환경 일관성 보장
  - 재시작 후에도 유지
  - 자동 만료 (TTL)

문서:
- CLAUDE.md Security 섹션 추가
- KV Namespace 설정 가이드 추가
- 배포/마이그레이션 가이드 추가

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-19 15:20:14 +09:00
parent 6d4fd7f22f
commit 4eb5bbd3d3
11 changed files with 1277 additions and 66 deletions

192
SUMMARY.md Normal file
View File

@@ -0,0 +1,192 @@
# Rate Limiting KV Migration - 작업 완료 요약
## 작업 개요
Rate Limiting 시스템을 인메모리 Map에서 Cloudflare KV로 마이그레이션하여 분산 환경에서 일관된 동작을 보장합니다.
---
## 변경 사항 요약
### 해결된 문제
✅ Workers 인스턴스 간 Rate Limit 데이터 공유
✅ Worker 재시작 시에도 Rate Limit 상태 유지
✅ 분산 환경에서 일관된 Rate Limiting 동작
✅ 자동 만료 (KV TTL) - 메모리 효율성
### 수정된 파일 (4개)
1. **`wrangler.toml`** - KV Namespace 바인딩 추가
2. **`src/types.ts`** - Env 인터페이스에 RATE_LIMIT_KV 추가
3. **`src/security.ts`** - checkRateLimit() 함수 KV 기반으로 재구현
4. **`src/index.ts`** - checkRateLimit() 호출 시 KV 전달
### 문서 업데이트
- **`CLAUDE.md`** - Rate Limiting 섹션, Configuration 섹션 업데이트
- **`KV_MIGRATION_GUIDE.md`** - 상세 마이그레이션 가이드 (신규)
- **`DEPLOYMENT_SUMMARY.md`** - 배포 절차 요약 (신규)
---
## 배포 가이드
### 1. KV Namespace 생성 (최초 1회)
```bash
wrangler kv:namespace create RATE_LIMIT_KV
```
출력된 `id` 값을 복사합니다.
### 2. wrangler.toml 수정
22번 줄의 `YOUR_KV_NAMESPACE_ID`를 실제 ID로 변경:
```toml
[[kv_namespaces]]
binding = "RATE_LIMIT_KV"
id = "abc123def456ghi789jkl012mno345pq" # ← 실제 ID로 변경
```
### 3. 로컬 테스트
```bash
npm run dev
```
다른 터미널에서 테스트:
```bash
curl -X POST http://localhost:8787/webhook \
-H "Content-Type: application/json" \
-H "X-Telegram-Bot-Api-Secret-Token: YOUR_WEBHOOK_SECRET" \
-d '{"update_id":1,"message":{"message_id":1,"from":{"id":123,"is_bot":false,"first_name":"Test"},"chat":{"id":123,"type":"private"},"date":1234567890,"text":"테스트"}}'
```
### 4. Production 배포
```bash
npm run deploy
```
### 5. 배포 확인
```bash
# Health Check
curl https://telegram-summary-bot.kappa-d8e.workers.dev/health
# 로그 확인
npm run tail
```
---
## 기술 상세
### Rate Limiting 알고리즘
**Key 형식:** `ratelimit:{userId}`
**데이터:**
```typescript
{
count: number, // 현재 윈도우 내 요청 수
resetAt: number // 윈도우 만료 시각 (Unix ms)
}
```
**동작:**
1. KV에서 사용자별 카운터 조회
2. 윈도우 만료 확인 (`now > resetAt`)
- 만료 시: 새 윈도우 시작 (`count=1`)
- 유효 시: count 증가
3. `count >= 30` → Rate Limit 초과, 차단
4. `count < 30` → KV 업데이트, 허용
**자동 만료:** KV의 `expirationTtl` 사용 (60초)
**에러 처리:** KV 오류 시 요청 허용 (가용성 우선)
---
## 성능 영향
| 항목 | Before (Map) | After (KV) |
|------|--------------|------------|
| 응답 시간 | ~1ms | ~20-50ms |
| 메모리 | 인스턴스별 | 0 (KV) |
| 일관성 | ❌ 분산 불일치 | ✅ 전역 일관성 |
| 재시작 | ❌ 데이터 손실 | ✅ 유지 |
**결론:** 약 20-50ms 지연 추가되지만, Telegram Webhook은 200ms 이내 응답 권장이므로 충분히 허용 가능.
---
## 비용 분석
### Cloudflare Workers Free Plan
- KV 읽기: 100,000 reads/day (무료)
- KV 쓰기: 1,000 writes/day (무료)
### 예상 사용량
- 1 메시지 = 1 read + 1 write
- 일일 1,000 메시지까지 무료
- 현재 사용량: ~100 메시지/일 → **$0 (무료)**
---
## 모니터링
### KV Dashboard
https://dash.cloudflare.com → Workers & Pages → KV → telegram-summary-bot-RATE_LIMIT_KV
### CLI 명령어
```bash
# Namespace 목록
wrangler kv:namespace list
# 특정 사용자 Rate Limit 조회
wrangler kv:key get "ratelimit:821596605" --namespace-id=YOUR_KV_ID
# 모든 키 목록
wrangler kv:key list --namespace-id=YOUR_KV_ID
# 로그 확인
wrangler tail
```
---
## 롤백 절차 (문제 발생 시)
```bash
git revert HEAD
npm run deploy
```
또는 수동 롤백:
1. `wrangler.toml`에서 KV Namespace 제거
2. `src/types.ts`, `src/security.ts`, `src/index.ts` 이전 버전 복원
3. `npm run deploy`
---
## 체크리스트
### 배포 전
- [ ] `wrangler kv:namespace create RATE_LIMIT_KV` 실행
- [ ] `wrangler.toml`에 실제 KV Namespace ID 입력
- [ ] 로컬 테스트 (`npm run dev`) 성공
### 배포 후
- [ ] `npm run deploy` 성공
- [ ] Health Check 정상
- [ ] 실제 Telegram 메시지 테스트
- [ ] KV Dashboard에서 키 생성 확인
- [ ] 30회 연속 메시지로 Rate Limit 동작 확인
---
## 추가 리소스
- **상세 가이드:** `KV_MIGRATION_GUIDE.md`
- **배포 요약:** `DEPLOYMENT_SUMMARY.md`
- **프로젝트 문서:** `CLAUDE.md`, `README.md`
- **Cloudflare KV Docs:** https://developers.cloudflare.com/kv/
---
**작업 완료 시각:** 2026-01-19
**상태:** ✅ 코드 변경 완료 / ⏳ 배포 대기 중
**다음 단계:** KV Namespace 생성 → wrangler.toml 수정 → 배포