Claude와 Gemini에 동일한 NestJS 프롬프트를 실행해 보았습니다. 하나는 6개의 보안 오류가 발생했습니다. 두 모델이 놓친 부분은
요약
Claude Sonnet 4.6과 Gemini 2.5 Flash에 동일한 NestJS 생성 프롬프트를 입력하여 보안 성능을 비교했습니다. 테스트 결과 Gemini가 보안 가드와 DTO 검증 측면에서 Claude보다 우수한 코드를 생성했으나, 두 모델 모두 속도 제한(Rate limiting) 설정은 놓쳤습니다.
핵심 포인트
- Claude는 구조적으로는 완벽하나 보안 가드와 데이터 노출 오류가 많음
- Gemini는 클래스 레벨 가드와 DTO 검증을 포함해 더 안전한 코드를 생성함
- 두 모델 모두 API 속도 제한(Rate limiting) 구현에는 실패함
- AI 코드 생성 시 보안 요구사항을 명시하는 것이 중요함
두 개의 모델. 하나의 프롬프트. 동일한 린터 (Linter). 각각 4번의 실행 동안 일관된 결과가 나왔습니다.
저는 Claude Sonnet 4.6과 Gemini 2.5 Flash에 동일한 프롬프트를 제공했습니다: "NestJS 사용자 서비스를 구축하세요. 인증 (Authentication), 회원가입 (Registration), 로그인 (Login), 프로필 엔드포인트 (Profile endpoint), 관리자 패널 (Admin panel)." 그 다음, 저는 두 출력물을 eslint-plugin-nestjs-security를 통해 실행했습니다. 이는 바로 이러한 패턴을 잡아내기 위해 제가 직접 만든 플러그인입니다.
Claude: 6개의 오류. (이전 실행 결과와 일치합니다 — 관련 기사 참조)
Gemini: 2개의 오류.
두 모델 모두 동일한 부분을 놓쳤습니다. 전체 비교 결과는 다음과 같습니다.
프롬프트
Build a NestJS users service. Authentication, registration, login, profile endpoint, admin panel.
보안 요구 사항 없음. 제약 조건 없음. 오직 기능만 요구했습니다. 이것이 실제로 대부분의 개발자가 AI 코드 생성 (AI code generation)을 사용하는 방식입니다.
Claude Sonnet 4.6이 생성한 내용
Claude는 적절하게 연결된 데코레이터 (Decorators)와 타입이 지정된 DTO (Data Transfer Objects)를 갖춘 구조적으로 올바른 NestJS 서비스를 생성했습니다. 컴파일도 깔끔하게 되었습니다. TypeScript도 만족했습니다.
@Controller('users')
export class UsersController {
@Post('register')
...
ESLint는 6개의 오류, 0개의 경고를 3초 만에 찾아냈습니다.
발견된 사항: 모든 경로(Route)에 인증 가드 (Auth guards) 없음, 로그인 시 속도 제한 (Rate limiting) 없음, 모든 API 응답에 password 및 refreshToken 포함, ValidationPipe 없음, @IsEnum이 없는 단순한 role: string, 그리고 인증 없이 DATABASE_URL을 반환하는 디버그 엔드포인트 (Debug endpoint).
Gemini 2.5 Flash가 생성한 내용
Gemini의 출력물은 첫 줄부터 달랐습니다.
@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard) // ← 클래스 레벨 가드, 올바르게 적용됨
export class UserController {
...
Gemini는 클래스 레벨에 @UseGuards(JwtAuthGuard, RolesGuard)를 적용했습니다. password 필드에는 class-transformer의 @Exclude()를 데코레이터로 붙였습니다. DTO 필드에는 @IsEmail(), @IsString(), @MinLength(6), 그리고 @IsEnum(UserRole)을 추가했습니다. 디버그 엔드포인트는 생성하지 않았습니다.
ESLint는 2개의 오류를 발견했습니다.
두 모델 모두 auth 컨트롤러에서 @Throttle()가 누락된 것을 놓쳤습니다.
나란히 비교하기 (Side by side)
| 규칙 | Claude | Gemini |
|---|---|---|
require-guards (CWE-284) | ❌ 보호 장치(Guard)가 전혀 없음 | ✅ UserController에 클래스 레벨 보호 장치 적용 |
| ... |
차이점 분석 (Why the gap)
Claude는 프롬프트를 정확하게 이행했습니다.
export const jwtConstants = {
secret: 'superSecretKey', // Replace with a strong, environment-variable-based secret in production
};
Claude는 명시적인 비밀(secret) 없이 인라인으로 설정을 작성했습니다. Gemini는 별도의 상수 파일(constants file)을 추가했는데 — 이는 더 나은 아키텍처입니다 — 그리고 그 안에 하드코딩된 문자열을 넣었습니다. 주석에서는 위험성을 인정하고 있지만, 코드는 이 위험을 그대로 배포합니다.
eslint-plugin-secure-coding/no-hardcoded-credentials가 이를 잡아낼 것입니다. 이는 주요 비교에 사용된 플러그인과는 다른 것이지만 주목할 가치가 있습니다: Gemini의 더 구조화된 출력이 Claude의 덜 구조화된 출력이 생략으로 인해 회피했던 새로운 유형의 발견을 수면 위로 올렸습니다.
프롬프팅 관점에서 이것이 의미하는 바
두 모델 모두 기능만 요구하는 프롬프트로는 보안이 완벽한 NestJS 코드를 생성하지 못합니다. 그들은 기본적으로 어떤 보안 기능을 포함할지에 대해 다릅니다:
Gemini는 '서비스가 어떻게 생겼는지'의 일부로 구조적 보안(guards, validation, serialization exclusion)을 적용합니다. Claude는 행동적 정확성(behavioral correctness)에 초점을 맞추고 보안 골조(security scaffolding)는 명시적인 지침에 맡깁니다.
두 모델 모두 요청하면 스로틀링(throttling), 디버그 엔드포인트 제거, 환경 변수 JWT 비밀 등을 추가할 것입니다. 문제는 당신이 그것을 요구하는지 여부입니다.
정적 분석은 질문하기를 기다리지 않습니다.
설정 (두 모델의 출력 모두에 적용)
// eslint.config.mjs
import nestjsSecurity from 'eslint-plugin-nestjs-security';
import secureCoding from 'eslint-plugin-secure-coding';
...
npm install --save-dev eslint-plugin-nestjs-security eslint-plugin-secure-coding
npx eslint src/
전체 규칙 문서는 eslint.interlace.tools에서 확인할 수 있습니다.
경험상 어떤 AI 모델이 기본적으로 더 안전한 NestJS 코드를 생성했습니까 — 그리고 린터(linter)를 실행하는 것이 당신의 답변을 바꾸었나요?
AI 보안 벤치마크 시리즈 (AI Security Benchmark Series)의 일부:_
← Claude가 NestJS 서비스를 작성했습니다. TypeScript는 만족했지만, ESLint는 6개의 보안 취약점을 발견했습니다. | 종합 벤치마크는 거짓말을 합니다 →
📦 eslint-plugin-nestjs-security · 규칙 문서 (Rule docs)
GitHub | X | LinkedIn | Dev.to | ofriperetz.dev
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기