chore: 테스트 편의를 위해 rate limit 을 분당 1000회로 완화

세 겹의 제한을 모두 분당 1000회로 상향(테스트 중 429 회피):
- main.ts express-rate-limit: 15분 150회 → 1분 1000회
- 전역 ThrottlerModule: 분당 100회 → 1000회
- 라우트별 @Throttle(login/signup/resend/forgot/reset/ai): 3~20회 → 1000회

각 라우트 주석에 운영 권장값을 남겨 추후 복원/ env 화 용이.
운영 배포 전 적정값으로 되돌릴 것.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 01:27:41 +09:00
parent d0599787f7
commit 861c8efa6b
5 changed files with 18 additions and 16 deletions
+2 -1
View File
@@ -57,10 +57,11 @@ import { ProjectModule } from './modules/project/project.module';
},
}),
// 전역 Rate Limiter — main.ts 의 express-rate-limit 와 별개로 라우트 단위 제어 가능
// NOTE: 개발/테스트 편의를 위해 분당 1000회로 완화함. 운영 배포 전 적정값으로 되돌릴 것.
ThrottlerModule.forRoot([
{
ttl: 60_000,
limit: 100,
limit: 1000,
},
]),
TypeOrmModule.forRootAsync({
+3 -2
View File
@@ -70,10 +70,11 @@ async function bootstrap() {
});
// 3. 글로벌 Rate Limiting 적용 (DDoS, 브루트포스 예방)
// NOTE: 개발/테스트 편의를 위해 분당 1000회로 완화함. 운영 배포 전 적정값으로 되돌리거나 env 화 필요.
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15
max: 150, // 15분 IP당 최대 150개 요청
windowMs: 60 * 1000, // 1분
max: 1000, // 1분 IP당 최대 1000개 요청
message: {
success: false,
error: {
@@ -23,7 +23,7 @@ export class AiSuggestController {
@Post('suggest-checklist')
@HttpCode(HttpStatus.OK)
@Throttle({ default: { limit: 20, ttl: 60_000 } })
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '할 일(체크리스트) 추천 — 프로젝트·업무 기반' })
@ApiResponse({ status: 200, description: '카테고리별 추천 항목' })
@ApiResponse({ status: 404, description: '프로젝트 없음 (RES_001)' })
+2 -2
View File
@@ -58,7 +58,7 @@ export class AiController {
@Post()
@HttpCode(HttpStatus.CREATED)
@Throttle({ default: { limit: 20, ttl: 60_000 } })
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '새 대화 시작 (첫 메시지)' })
@ApiResponse({ status: 201, description: '생성 + AI 응답' })
start(
@@ -70,7 +70,7 @@ export class AiController {
@Post(':id/messages')
@HttpCode(HttpStatus.OK)
@Throttle({ default: { limit: 20, ttl: 60_000 } })
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '대화에 메시지 추가' })
@ApiResponse({ status: 200, description: 'AI 응답' })
@ApiResponse({ status: 404, description: '대화 없음 (RES_001)' })
+10 -10
View File
@@ -95,8 +95,8 @@ export class AuthController {
@Post('signup')
@HttpCode(HttpStatus.CREATED)
// 가입 남용/메일 폭탄 방지 — IP당 분당 5회
@Throttle({ default: { limit: 5, ttl: 60_000 } })
// 가입 남용/메일 폭탄 방지 — 운영 권장 5회/분 (현재 테스트용 1000회로 완화)
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '회원가입 (인증 메일 발송, 자동 로그인 안 함)' })
@ApiResponse({ status: 201, description: '가입 접수 — 인증 메일 발송됨' })
@ApiResponse({ status: 409, description: '이미 가입된 이메일 (BIZ_001)' })
@@ -107,8 +107,8 @@ export class AuthController {
@Post('resend-verification')
@HttpCode(HttpStatus.OK)
// 메일 폭탄 방지 — IP당 분당 3회
@Throttle({ default: { limit: 3, ttl: 60_000 } })
// 메일 폭탄 방지 — 운영 권장 3회/분 (현재 테스트용 1000회로 완화)
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '인증 메일 재발송' })
@ApiResponse({ status: 200, description: '재발송 접수(존재 여부 비노출)' })
async resend(@Body() dto: ResendVerificationDto): Promise<null> {
@@ -118,8 +118,8 @@ export class AuthController {
@Post('forgot-password')
@HttpCode(HttpStatus.OK)
// 메일 폭탄/계정 탐색 방지 — IP당 분당 3회
@Throttle({ default: { limit: 3, ttl: 60_000 } })
// 메일 폭탄/계정 탐색 방지 — 운영 권장 3회/분 (현재 테스트용 1000회로 완화)
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '비밀번호 재설정 요청 (재설정 메일 발송)' })
@ApiResponse({ status: 200, description: '요청 접수(존재 여부 비노출)' })
async forgotPassword(@Body() dto: ForgotPasswordDto): Promise<null> {
@@ -129,8 +129,8 @@ export class AuthController {
@Post('reset-password')
@HttpCode(HttpStatus.OK)
// 토큰 추측 방지 — IP당 분당 5회
@Throttle({ default: { limit: 5, ttl: 60_000 } })
// 토큰 추측 방지 — 운영 권장 5회/분 (현재 테스트용 1000회로 완화)
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '비밀번호 재설정 (토큰 + 새 비밀번호)' })
@ApiResponse({ status: 200, description: '비밀번호 변경 성공' })
@ApiResponse({ status: 400, description: '토큰 만료/무효 (BIZ_001)' })
@@ -158,8 +158,8 @@ export class AuthController {
@Post('login')
@HttpCode(HttpStatus.OK)
// 무차별 대입 방지 — IP당 분당 10회
@Throttle({ default: { limit: 10, ttl: 60_000 } })
// 무차별 대입 방지 — 운영 권장 10회/분 (현재 테스트용 1000회로 완화)
@Throttle({ default: { limit: 1000, ttl: 60_000 } })
@ApiOperation({ summary: '로그인' })
@ApiResponse({ status: 200, description: '로그인 성공, 인증 쿠키 발급' })
@ApiResponse({