승인 우회를 막으려다 배운 것: 증거가 있으면 못 빠져나간다
관리자 승인 우회를 막는 과정에서 검증 순서를 헤더 전으로 옮기고 전송 이력 전체를 보게 만든 1인 개발 빌드로그입니다.
승인 버튼 하나 만드는 데 일주일을 썼습니다. 정확히는 2026년 9월 13일부터 19일까지, 커밋 16건 중 절반 가까이가 "승인"이라는 단어를 달고 있어요. 버튼이 어려운 게 아니라, 승인을 우회할 수 있는 길이 계속 나왔다는 게 문제였습니다.
처음엔 "관리자니까 통과"로 만들었습니다
자동화 파이프라인에서 콘텐츠를 발행하기 전에 사람이 한 번 보고 승인하는 구조를 만들었어요. 급할 때 막히면 안 되니까 관리자 권한이면 그냥 통과시키는 경로를 하나 열어뒀습니다.
직접 돌려 보니 이게 문제였습니다. 우회가 기록 없이 일어나니까, 나중에 "이거 왜 나갔지?"를 되짚을 방법이 없었어요. 그래서 9월 15일 커밋에서 우회 자체를 막는 대신 기록된 예외로 바꿨습니다. 통과는 되지만 흔적이 남게요.
진짜 구멍은 "본 것"과 "승인한 것"이 달랐다는 점
여기서 더 불편한 걸 발견했습니다. 사람이 화면에서 본 본문과, 실제로 승인 처리되는 본문이 같다는 보장이 없었어요. 중간에 리비전이 바뀌면 그냥 어긋납니다.
그래서 표시 본문을 앱이 조립하지 않고 DB가 리비전에서 직접 파생하도록 바꿨습니다. 사람이 본 화면과 승인 대상을 같은 출처에 묶은 거예요. 이 커밋 하나에 마이그레이션 2개와 스크립트 3개가 같이 움직였습니다. 작아 보이는 변경인데 손대는 파일 수는 5개였어요.
적용해 봤더니 사고 방식이 바뀌더군요. "화면이 맞나"가 아니라 "화면과 결정이 같은 뿌리에서 나오나"를 묻게 됩니다.
검증 순서를 뒤로 미루면 안 됩니다
마지막까지 남은 게 9월 19일 커밋입니다. 헤더를 먼저 만들고 나서 본문을 검증하는 순서였는데, 이러면 검증에서 떨어진 항목이 이미 헤더에 반영된 뒤예요.
테스트해 보면 바로 드러납니다. 조용히 빠진 항목은 로그에도 안 남아요. 그래서 두 가지를 했습니다.
- 검증을 실제 렌더 조건과 같게 맞추기 — 검증 통과 기준과 실제 출력 기준이 다르면 검증이 아니죠
- 드롭 건수를 표면에 드러내기 — 몇 개가 왜 빠졌는지 안 보이면 없는 일이 됩니다
- 기록된 예외
- 같은 출처에서 파생
- 검증은 렌더 전에
일주일 돌아보며 남은 것
세 문장으로 줄이면 이렇습니다.
- 우회를 막는 것보다 우회에 흔적을 남기는 게 현실적입니다.
- 사람이 본 것과 시스템이 처리하는 것은 같은 출처에서 나와야 합니다.
- 검증은 결과를 만들기 전에 돌아야 하고, 떨어진 건수를 사람이 봐야 합니다.
1인 개발이라 리뷰어가 없으니까, 이런 건 결국 "나중의 내가 추적할 수 있나"로 판단하게 되더군요. 라이프케어로그에서 만드는 플랜씨(무료 금융계산기)나 플랜엘(법령·판례 검색) 같은 서비스도 결국 같은 원칙 위에 있어요. 사용자가 본 숫자와 계산된 숫자가 다르면 계산기가 아니니까요.
다음은 이 승인 흐름에 걸린 예외들을 한 번 모아서 보는 작업입니다. 기록만 쌓고 안 보면 그것도 없는 일이거든요. 🙂
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.