take.crowny.org 자산 설계 3종 — 이미지추적 · JSON최적화 · 보안하드닝
상태: 설계만(미구현·미배포). take.crowny.org 자산으로 등재. 외부배포(takeurban.art)는 현 상황 유지.
결정(2026-06-28): PG=비교만·결제보류 / 백업=한 계정 시험운영 후 2VPS는 이후 / 세 설계=자산 등재.
구현 시 순서·검증항목·한선씨 동반까지 이 문서로 바로 빌드 가능하게 작성.
설계 1 — 이미지 다운로드 추적(워터마킹)
목표: 사용자가 이미지를 다운로드할 때 로그인 id + 다운로드 시간을 이미지/기록에 남겨, 이후 도용 시 추적 가능하게.
3층 구조 (각 한계 명시)
| 층 | 방법 | 강점 | 한계 |
|---|
| ① 감사로그(서버) | 인증 다운로드마다 기록 | 최강 증거·쉬움 | 이미지 자체엔 표식 없음 |
| ② 가시 워터마크 | id+시간 반투명 합성(클라 Canvas) | 즉각 억지·육안추적 | 크롭/스샷 제거 |
| ③ 메타 표식 | JPEG COM마커에 서명 페이로드(순수 바이트) | 비가시·0의존성 | 재인코딩 소실 |
데이터 모델
data/download_log.jsonl (append-only, 1줄=1다운로드): {ts, owner(=userId), blobId, ip, ua, sig}
sig = HMAC_SHA256(TAKE_DL_KEY, owner|blobId|ts) — 사후 위조 판별용.
API 설계
GET /api/blob/<id>?dl=1 — owner 헤더 필수(미인증 403). 처리: ① 감사로그 append ② JPEG면 COM마커에 crowny-dl:owner|ts|sig 삽입(순수 바이트, PNG는 tEXt 청크) ③ 응답.
- 클라 다운로드 버튼: 원본 → Canvas에 그림 + 우하단 반투명 텍스트(
id · YYYY-MM-DD HH:mm) → toBlob → 저장(②). 원본 raw blob 접근은 인증·로그로 봉쇄.
- 사후 추적: 유출 이미지의 COM마커 또는 로그 대조 → owner·시각 식별, sig로 위조 배제.
한선씨 동반 (설계)
추적표식.한선 — 다운로드 4상 판정 + 서명 계약:
함수 다운로드판정(인증됨, 차단여부) // 1=허용(티)/0=인증필요(옴)/-1=차단(타)/9=의심(음)
함수 표식페이로드(소유자, 시각) // "owner|ts" 조립
// 서명 자체(HMAC)는 server.js crypto 위임(한선씨는 판정·조립 SSOT)
검증항목(구현 시)
COM마커 왕복 보존 · 로그 append 멱등 · sig 위조 거부 · 미인증 403 · PNG/JPEG 분기.
솔직한 한계
스크린샷·재압축이면 ②③ 소실.
법적 추적 최강은 ①감사로그. 권장 기본 = ①+②, ③ 선택.
설계 2 — JSON 최적화
현실: JSON은 이미 전체의 0.x%(이미지가 본체). 실효 이득은
용량보다 처리비용.
조치(무위험 순)
- 콤팩트 JSON —
JSON.stringify(o, null, 2) → JSON.stringify(o). 공백 제거로 ~20~40%↓. atomicWrite 경유 전부 적용.
- 주문 인덱스 —
data/orders/_index.jsonl(1줄=요약 {id,status,createdAt,updatedAt,owner,unanswered}). saveOrder 시 upsert, allOrders()(현재 전 파일 동기 전수읽기)는 인덱스만 읽음 → 목록 O(n 디스크) → O(1 파일). 상세는 조회 시만 개별 로드.
- 콜드데이터 압축 — N일 지난 주문/아카이브 특가
.json.gz(또는 크라우니압축기 .ccp). 조회 시 해제.
- (규모 시) node:sqlite(Node22 내장, 외부의존성 0) 마이그레이션 경로 — 인덱스·트랜잭션. 지금 불필요.
효과 추정
pretty 제거 ~20-40%↓ · 인덱스로 관리자 목록 응답 급감(현 병목 allOrders 해소) · 0 의존성 유지.
한선씨 동반 (설계)
인덱스는 데이터라 판정 적음.
보관정책.한선 — 압축 대상 4상 판정(티즉시/옴보관/타압축/음삭제후보, 날짜·상태 기준) 정도.
검증항목
인덱스↔실파일 정합 · 콤팩트 전환 후 파싱 회귀0 · 압축 왕복 byte-identical.
설계 3 — 보안 하드닝
현황 실측 — 됨: scrypt·40자 owner토큰·부팅랜덤 관리자세션·경로조작가드(safeId)·업로드검증·번들 data제외.
없음: 레이트리밋·보안헤더·PII평문·로그회전.
모듈 설계
보안게이트.한선 — 레이트리밋 4상: 로그인/주문 IP별 윈도우 카운트 → 티(허용)/옴(지연·캡차)/타(거절)/음(임시밴). 카운터는 server.js 메모리맵 위임, 판정은 한선씨 SSOT.
- 보안헤더 미들웨어(엔진 공통화 가능) — CSP, HSTS, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy. (nginx/stunnel 단에서도 병행)
- PII 암호화 — profiles/users의
전화번호·주소·통관번호·이름·입금자명 = AES-256-GCM(키=env TAKE_PII_KEY). 저장 시 암호화·조회 시 복호화. 마이그레이션 스크립트(기존 평문→암호문, 1회). 로그 PII 마스킹.
- admin 기본비번 가드 — 부팅 시 비번이 기본값(
take1004)이면 경고 로그 + (옵션)기동거부 env.
- 로그 회전 —
take.err/take.log 크기상한 회전(자체 구현 or VPS logrotate). 현재 take.err 6.3MB 무한증가 해소.
- 보안 감사로그 — 로그인 실패·관리자 액션 기록.
- 적대 테스트 — 기존 crowny-spear 규칙엔진으로 공격검증(설계 검증단계 포함).
우선순위(구현 시)
즉시(무위험): admin비번 변경 + 로그회전 → 보안게이트(레이트리밋+헤더) → PII 암호화(마이그레이션 동반).
검증항목
레이트리밋 임계 동작 · 헤더 응답 확인 · PII 왕복 암복호 + 마이그레이션 무손실 · spear 공격 통과.
자산 등재 메모
- 자산 소유: take.crowny.org (/Users/ef/crowny-take). 외부배포(takeurban.art VPS)는 현 준비상태 유지(자족화·배포.sh 완료, 미실행).
- 구현 트리거: 사용자 지시 시 이 문서 순서대로. 모두 한선씨 동반 + 검증 후 라이브 반영.
- 관련: PG 비교(토스/나이스/PayGate 파사드)는 결제 보류 결정 — 별도 자산(요청 문서).