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:
192
SUMMARY.md
Normal file
192
SUMMARY.md
Normal 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 수정 → 배포
|
||||
Reference in New Issue
Block a user