데브포일 홈
DEV MODE - 실서버 영향 없음 📦 배포 관리
엔터프라이즈 보안과 감사 로그
+450 XP
LEVEL 87 QUEST

엔터프라이즈 보안과 감사 로그

엔터프라이즈 보안과 감사 로그 — DevFoil 바이브코딩 Stage 18, Lv.87

감사 로그(Audit Log) 설계
"누가, 언제, 무엇을, 어떻게" 변경했는지 모두 기록
감사 로그(Audit Log)는 시스템에서 발생하는 모든 중요한 활동을 기록하는 시스템입니다. 엔터프라이즈 고객에게는 필수 요구사항이며, 보안 사고 대응과 규정 준수(컴플라이언스)에 핵심적입니다.

감사 로그에 기록해야 할 이벤트:
  • 인증 이벤트: 로그인 성공/실패, 로그아웃, 비밀번호 변경
  • 데이터 변경: 생성, 수정, 삭제 (변경 전/후 값 포함)
  • 권한 변경: 역할 부여/제거, 팀 멤버 추가/삭제
  • 설정 변경: 보안 설정, 과금 플랜 변경
  • 데이터 접근: 민감 데이터 조회 (GDPR 관련)
// 감사 로그 스키마 model AuditLog { id String @id @default(cuid()) tenantId String userId String? // 시스템 이벤트는 null action String // 'user.login', 'project.update', 'member.role_changed' resource String // 'user', 'project', 'member' resourceId String? // 대상 리소스 ID details Json // 변경 상세 (before/after) ipAddress String? userAgent String? severity AuditSeverity @default(INFO) timestamp DateTime @default(now()) @@index([tenantId, timestamp]) @@index([tenantId, action]) @@index([userId, timestamp]) } enum AuditSeverity { INFO // 일반 활동 WARNING // 주의 필요 (로그인 실패 등) CRITICAL // 긴급 (권한 변경, 데이터 삭제 등) }
감사 로그 자동 기록 시스템
수동 기록이 아닌, 미들웨어로 자동 기록
각 API에서 일일이 로그를 기록하면 빠뜨리기 쉽습니다. 미들웨어와 이벤트 시스템을 활용하면 자동으로 모든 활동이 기록됩니다.
// auditLogger.ts class AuditLogger { // 감사 로그 기록 async log(params: { tenantId: string; userId?: string; action: string; resource: string; resourceId?: string; details?: object; severity?: string; req?: Request; }) { await db.auditLog.create({ data: { tenantId: params.tenantId, userId: params.userId, action: params.action, resource: params.resource, resourceId: params.resourceId, details: params.details || {}, severity: params.severity || 'INFO', ipAddress: params.req?.ip, userAgent: params.req?.headers['user-agent'] } }); } // 데이터 변경 시 before/after 자동 비교 async logChange(params: { tenantId: string; userId: string; action: string; resource: string; resourceId: string; before: object; after: object; req?: Request; }) { const changes = this.diff(params.before, params.after); if (Object.keys(changes).length === 0) return; // 변경 없으면 기록 안함 await this.log({ ...params, details: { before: params.before, after: params.after, changes }, severity: 'INFO' }); } // 두 객체의 차이점 추출 private diff(before: any, after: any) { const changes: Record<string, { old: any; new: any }> = {}; for (const key of Object.keys(after)) { if (JSON.stringify(before[key]) !== JSON.stringify(after[key])) { changes[key] = { old: before[key], new: after[key] }; } } return changes; } } export const auditLogger = new AuditLogger(); // 사용 예시 app.put('/api/projects/:id', async (req, res) => { const before = await db.project.findUnique({ where: { id: req.params.id } }); const after = await db.project.update({ where: { id: req.params.id }, data: req.body }); await auditLogger.logChange({ tenantId: req.tenantId, userId: req.user.id, action: 'project.update', resource: 'project', resourceId: req.params.id, before, after, req }); res.json(after); });
🔒
여기까지는 미리보기입니다
엔터프라이즈 보안과 감사 로그
무료 가입하면 이어서 볼 수 있고, 강의를 완료할 때마다 XP와 레벨이 쌓입니다.
Google로 3초 만에 시작 →🧵 Threads로 시작무료 공개 강의 둘러보기 (Lv.1~3)