유대선
프로젝트로
·기술 회고·3 ·리뷰 필요

적대적 보안 리뷰: 11개 확인 결함과 무엇을 지금 고쳤나

빌드 후 다중 에이전트 적대적 리뷰(보안/인증/데이터/캡처/PWA/스펙)를 돌려 11개 결함을 확인. 데모/스펙을 깨는 것 위주로 즉시 수정, 프로덕션 스케일 항목 2개는 문서화.

AI 버전

e1a924e로 앱이 동작한 뒤, 6개 차원(보안/인증/데이터/캡처/PWA/스펙)으로 적대적 리뷰를 돌리고 각 발견을 독립 검증 후에만 채택했다. 확인된 결함 11개. 전부 코드를 직접 읽어 검증.

즉시 수정 (모두 ed3600c)

결함검증수정
dev-login 프로덕션 인증우회라우트에 NODE_ENV 가드 없음 → 이메일만으로 타인 보관함 세션 발급프로덕션 notFound() 가드
업로드 MIME 미검증 → 저장형 XSS기여자 file.type이 그대로 저장·반사, svg/html 가능MIME 화이트리스트(isAllowedImageMime/Audio) + 미디어 응답 X-Content-Type-Options: nosniff
SW가 비공개 보관함 HTML 캐시navigate 분기가 모든 응답 caches.put → 로그아웃/공용기기 유출network-only + 오프라인 폴백, 캐시 v1→v2로 기존 정리
미디어 라우트 Range 무시(iOS 재생 깨짐)Accept-Ranges 광고하면서 항상 200Range 파싱 → 206 + Content-Range
CSRF 무방비상태변경에 쿠키가 유일 권한, Origin 검사 없음proxy.ts(Next 16, 구 middleware)로 same-origin 강제
rate limit 토큰별 없음 + 본문 무제한 버퍼공개 엔드포인트토큰별 throttle + 본문 Content-Length 조기 차단
부분 env가 세션비밀 재생성SESSION_SECRET만 줘도 무시되던 all-or-nothing키별 개별 적용
AudioRecorder가 모든 실패를 '마이크 거부'로recordFailed 카피가 dead code(§18 위반)err.name 구분 + 언마운트 안전

검증 방법(직접 실행): evil Origin POST → 403, same-origin → 200; text/html as photo → 400; curl -H "Range: bytes=0-99"206/content-range; 미인증 미디어 → 401.

지금 안 고치고 문서화 (프로덕션 스케일 한정, 데모 영향 없음)

  • 알림 dedupe 영속화: 현재 인메모리(단일 프로세스 OK). 다중 인스턴스/재시작엔 중복 발송 가능 → (reminderId, 날짜, HH:MM) 영속 마커 필요. 현재 PGlite는 단일 인스턴스라 데모엔 무영향.
  • 신뢰 프록시 IP: rate-limit 키가 X-Forwarded-For 원문 기반(스푸핑 가능) → 호스팅 신뢰 IP로. 토큰별 throttle로 부분 방어는 적용됨.

메모

  • 리뷰는 발견 → 독립 검증 → 채택 구조. "그럴듯하지만 틀린" 발견을 거르려 검증 단계를 분리했다.
  • 한 가지 정직한 한계: 위 수정들은 dev 서버 실행으로 검증했지만, 실제 공격 시나리오(예: 진짜 크로스사이트 폼)까지 재현하진 않았다 — Origin 검사·nosniff 같은 표준 방어를 코드로 확인한 수준.

리뷰 필요

내 시각이 아직 안 들어간 entry.