불변 설계: Health SaaS를 위한 변조 방지 감사 로그 구축
Source: Dev.to
잠시 현실을 직시해 봅시다: 아침에 일어나서 감사 로그 시스템을 구축하는 일에 신이 나는 사람은 없습니다. 우리는 모두 새로운 기능을 배포하거나, React 렌더링을 최적화하거나, 솔직히 말해서 그냥 늦잠을 자는 것을 더 선호합니다.
하지만 헬스테크 분야에서 일한다면 그 절차를 잘 알 겁니다. HIPAA, GDPR, SOC2… 이것들은 단순한 약어가 아니라 여러분 비즈니스의 문지기입니다.
구시대적인 “로그” 방식? JSON을 텍스트 파일이나 S3 버킷에 덤프하는 것입니다. 문제는? rm -rf /var/logs. 더 심각한 경우는 악의적인 관리자 시나리오—루트 접근 권한을 가진 데이터베이스 관리자가 자신의 흔적을 지우기 위해 UPDATE 명령을 실행하면 어떻게 될까요? 감사 로그가 단순한 SQL 테이블에 불과하다면, 기록이 재작성되지 않았다는 것을 감사인에게 증명할 수 없습니다.
문제: 변경 가능한 데이터베이스
표준 Postgres 또는 MySQL 설정에서는 데이터가 설계상 변경 가능하도록 되어 있습니다. 이는 버그가 아니라 기능입니다. 하지만 규제된 환경에서 감사 추적을 위해서는 변경 가능성이 적입니다.
UPDATE audit_logs
SET action = 'authorized_access'
WHERE user_id = 'rogue_admin' AND action = 'access_denied';
실제로 기록이 변경되었다는 증거가 전혀 없습니다. 감사자는 “Is this record accurate?” 라고 묻고, 당신은 “I think so?” 라고 답합니다. 이는 의료 분야에서 통용되지 않을 것입니다.
전략 1: 암호 체이닝 (“DIY 블록체인”)
특정 데이터베이스를 도입할 준비가 되지 않았다면, SQL 데이터베이스 안에 “체인”을 구현할 수 있습니다. 이는 기본적으로 블록체인이 작동하는 방식이지만 중앙 집중식입니다.
스키마
CREATE TABLE strict_audit_log (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
action VARCHAR(255),
payload JSONB,
prev_hash VARCHAR(64), -- The hash of the previous row
curr_hash VARCHAR(64), -- The hash of this row (including prev_hash!)
created_at TIMESTAMP DEFAULT NOW()
);
로직
async function logAction(user, action, payload) {
// 1. Get the last record
const lastLog = await db.query(
'SELECT curr_hash FROM strict_audit_log ORDER BY id DESC LIMIT 1'
);
const prevHash = lastLog ? lastLog.curr_hash : '0000000000'; // Genesis block style
// 2. Create the hash for the new record
// We use SHA-256 here. Ensure your serialization is deterministic!
const dataString = `${user.id}${action}${JSON.stringify(payload)}${prevHash}`;
const currHash = crypto.createHash('sha256')
.update(dataString)
.digest('hex');
// 3. Insert
await db.query(
`INSERT INTO strict_audit_log (user_id, action, payload, prev_hash, curr_hash)
VALUES ($1, $2, $3, $4, $5)`,
[user.id, action, payload, prevHash, currHash]
);
}
왜 작동하는가: 악의적인 관리자가 테이블 중간(예: ID 500)의 행을 변경하면 해당 행의 해시가 바뀝니다. ID 501은 원래 ID 500의 해시를 포함하고 있기 때문에 체인이 끊어집니다. 매일 밤 체인을 순회하면서 무결성을 검증하는 스크립트를 실행할 수 있습니다.
작은 주의점: 이 방식은 직렬화 병목 현상을 초래합니다(쓰기 작업을 병렬화할 수 없음). 하지만 감사 로그의 경우 보통 허용 가능한 수준입니다.
이러한 백엔드 패턴에 대해 더 자세히 다룬 글은 제 개인 블로그 wellally.tech에서 확인할 수 있습니다.
전략 2: 전용 원장 데이터베이스 (QLDB)
DIY 접근 방식이 유지 관리가 너무 많다고 느껴지고(해시 레이스 조건을 처리하는 것이 번거롭다면) 원장 데이터베이스를 살펴보세요. Amazon QLDB(Quantum Ledger Database)가 여기서 강력한 선택입니다. 암호화 체인을 자동으로 수행하고 투명하고 불변이며 검증 가능한 트랜잭션 로그를 제공합니다.
아키텍처 변화 방식
Postgres 테이블에 쓰는 대신, 중요한 감사 이벤트를 PartiQL(SQL‑유사 구문)을 사용해 QLDB에 전송합니다.
-- PartiQL은 친숙하게 보입니다
INSERT INTO AuditTrail
VALUE {
'userId': '12345',
'action': 'VIEW_PATIENT_RECORDS',
'timestamp': '2025-10-22T10:00:00Z'
}
핵심은 Digest에 있습니다. 특정 시점에 데이터베이스의 암호화 서명을 다운로드할 수 있습니다. 감사자가 몇 달 뒤에 찾아오면, 그 다이제스트를 사용해 회사 내 누구도—CTO조차도—데이터를 변경하지 않았음을 수학적으로 증명할 수 있습니다.
어느 것을 선택해야 할까요?
- Startups / MVPs: SQL Chaining 방법(Strategy 1)부터 시작하세요. 스택이 단순해지고(새 인프라 관리 필요 없음) 텍스트 파일에 로그를 남기는 대부분의 경쟁자보다 앞서 나갈 수 있습니다.
- Enterprise / High Compliance: 병원과 BAA(비즈니스 파트너 계약)를 체결하고 있다면 QLDB 또는 Oracle/Azure SQL의 불변 테이블을 고려하세요. 검증 가능한 기능이 감사 시 많은 시간을 절약해 줍니다.
결론
규정 준수는 종종 부담으로 여겨지지만, 헬스테크에서는 신뢰의 한 요소입니다. 고객을 똑바로 바라보며 “나조차 이 데이터를 변경할 수 없습니다”라고 말할 수 있는 것은 강력한 영업 도구가 됩니다.
직접 해시‑체인을 구현하든 Ledger DB를 구축하든 목표는 동일합니다: 설계상 불변성.