스킬
보안 리뷰

보안 리뷰

다운로드 후 ~/.claude/skills/ 폴더에 복사하여 사용하세요

모든 코드가 보안 모범 사례를 따르고 잠재적 취약점을 식별하도록 보장합니다.

활성화 시점

  • 인증 또는 인가 구현
  • 사용자 입력 또는 파일 업로드 처리
  • 새 API 엔드포인트 생성
  • 시크릿 또는 자격 증명 작업
  • 결제 기능 구현
  • 민감한 데이터 저장 또는 전송

보안 체크리스트

1. 시크릿 관리

const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL
 
// 시크릿 존재 확인
if (!apiKey) {
  throw new Error('OPENAI_API_KEY가 설정되지 않았습니다')
}

검증 단계:

  • 하드코딩된 API 키, 토큰, 비밀번호 없음
  • 모든 시크릿이 환경 변수에 있음
  • .env.local이 .gitignore에 있음
  • git 히스토리에 시크릿 없음

2. 입력 검증

import { z } from 'zod'
 
// 검증 스키마 정의
const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
  age: z.number().int().min(0).max(150)
})
 
// 처리 전 검증
export async function createUser(input: unknown) {
  try {
    const validated = CreateUserSchema.parse(input)
    return await db.users.create(validated)
  } catch (error) {
    if (error instanceof z.ZodError) {
      return { success: false, errors: error.errors }
    }
    throw error
  }
}

파일 업로드 검증

function validateFileUpload(file: File) {
  // 크기 검사 (최대 5MB)
  const maxSize = 5 * 1024 * 1024
  if (file.size > maxSize) {
    throw new Error('파일이 너무 큽니다 (최대 5MB)')
  }
 
  // 타입 검사
  const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
  if (!allowedTypes.includes(file.type)) {
    throw new Error('잘못된 파일 타입')
  }
 
  return true
}

3. SQL 인젝션 방지

🚫

절대 SQL을 연결하지 마세요!

// 파라미터화된 쿼리
const { data } = await supabase
  .from('users')
  .select('*')
  .eq('email', userEmail)
 
// 또는 원시 SQL로
await db.query(
  'SELECT * FROM users WHERE email = $1',
  [userEmail]
)

4. 인증 & 인가

JWT 토큰 처리

// httpOnly 쿠키
res.setHeader('Set-Cookie',
  `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)

인가 검사

export async function deleteUser(userId: string, requesterId: string) {
  // 항상 먼저 인가 검증
  const requester = await db.users.findUnique({
    where: { id: requesterId }
  })
 
  if (requester.role !== 'admin') {
    return NextResponse.json(
      { error: '권한이 없습니다' },
      { status: 403 }
    )
  }
 
  // 삭제 진행
  await db.users.delete({ where: { id: userId } })
}

Row Level Security (Supabase)

-- 모든 테이블에 RLS 활성화
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
 
-- 사용자는 자신의 데이터만 볼 수 있음
CREATE POLICY "Users view own data"
  ON users FOR SELECT
  USING (auth.uid() = id);

5. XSS 방지

HTML 새니타이즈

import DOMPurify from 'isomorphic-dompurify'
 
// 항상 사용자 제공 HTML 새니타이즈
function renderUserContent(html: string) {
  const clean = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
    ALLOWED_ATTR: []
  })
  return <div dangerouslySetInnerHTML={{ __html: clean }} />
}

Content Security Policy

// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: `
      default-src 'self';
      script-src 'self' 'unsafe-eval' 'unsafe-inline';
      style-src 'self' 'unsafe-inline';
      img-src 'self' data: https:;
    `.replace(/\s{2,}/g, ' ').trim()
  }
]

6. CSRF 보호

import { csrf } from '@/lib/csrf'
 
export async function POST(request: Request) {
  const token = request.headers.get('X-CSRF-Token')
 
  if (!csrf.verify(token)) {
    return NextResponse.json(
      { error: '잘못된 CSRF 토큰' },
      { status: 403 }
    )
  }
 
  // 요청 처리
}

7. 레이트 리미팅

import rateLimit from 'express-rate-limit'
 
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15분
  max: 100, // 윈도우당 100 요청
  message: '요청이 너무 많습니다'
})
 
// 라우트에 적용
app.use('/api/', limiter)

8. 민감한 데이터 노출

// 민감한 데이터 마스킹
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
 
// 일반적인 오류 메시지
catch (error) {
  console.error('Internal error:', error)
  return NextResponse.json(
    { error: '오류가 발생했습니다. 다시 시도해 주세요.' },
    { status: 500 }
  )
}

9. 의존성 보안

# 취약점 확인
npm audit
 
# 자동 수정 가능한 이슈 수정
npm audit fix
 
# 의존성 업데이트
npm update
 
# CI/CD에서 재현 가능한 빌드를 위해 사용
npm ci  # npm install 대신

배포 전 보안 체크리스트

모든 프로덕션 배포 전:

  • 시크릿: 하드코딩된 시크릿 없음
  • 입력 검증: 모든 사용자 입력 검증됨
  • SQL 인젝션: 모든 쿼리 파라미터화됨
  • XSS: 사용자 컨텐츠 새니타이즈됨
  • CSRF: 보호 활성화됨
  • 인증: 적절한 토큰 처리
  • 인가: 역할 검사 적용됨
  • 레이트 리미팅: 모든 엔드포인트에 활성화됨
  • HTTPS: 프로덕션에서 강제됨
  • 보안 헤더: CSP, X-Frame-Options 설정됨
  • 오류 처리: 오류에 민감한 데이터 없음
  • 로깅: 로그에 민감한 데이터 없음
  • 의존성: 최신 상태, 취약점 없음

리소스

🚫

보안은 선택사항이 아닙니다. 하나의 취약점이 전체 플랫폼을 위험에 빠뜨릴 수 있습니다. 확신이 없으면 신중하게 선택하세요.