2026-07-29 세션 — P0 보안 3결정 실행(인증 게이트·시크릿·응답 규약) 운영배포
지시
페페 결정 3건:
1. platform-auth = 추천대로(A+C) + 하위 2건(secret_key, 무솔트 해시)도 추천안으로 보안처리
2. ops-secrets = 비번은 그대로, git에 있는 관리자 비번 삭제·gitignore 관리로 수정, C 진행(8791)
3. platform-response-policy = B(헬퍼만 먼저, 파트별 점진 이관)
→ "테스트 배포 후 검증 진행 후 운영배포 진행한다."
1. 착수 전 사실 확인 (게이트를 잘못 걸면 클라이언트가 죽는다)
api/pfs/*컨트롤러 49개 중login_required0건 재확인. before_request 훅도/api/면 통과.- API 를 부르는 외부 주체 전수: poin-agent
freight_worker.py·pfs_board_sync.py는 이미/api/auth/login후 세션 쿠키로 호출한다 → 게이트 영향 없음.print-agent는/static로고만 받는다 → 무관. 🔴orderpaper-sync/door_sync_watch.py만 무세션으로/api/sticker/sync-poll·/sync-complete폴링 → 이 두 경로가 게이트에 걸린다. 화이트리스트로 열어두면 무인증 구멍이 남으므로 공유 토큰을 쓰기로. user.password= varchar(1000) → pbkdf2 문자열(111자) 저장 가능, 스키마 변경 불필요. 전 계정 구형 64자(테스트 9 / 운영 10).- EC2 env 주입 경로 = 앱 루트
.env.production심볼릭 링크 →/home/ubuntu/env/pfs-{test,live}.env.
2. 구현
| 항목 | 내용 |
|---|---|
| A1 인증 게이트 | web/__init__.py before_request: 비로그인 /api/ → 401 JSON. 화면은 종전대로 각 라우트 login_required 위임. 데몬 경로 2개만 X-PFS-Agent-Token 검증(hmac.compare_digest) |
| A2 secret_key | 리터럴 제거 → PFS_SECRET_KEY env. 서버(test/live)인데 미설정이면 Log.error 로 드러냄 |
| A3 비번 해시 | hash_password(pbkdf2-sha256, 솔트 16B, 20만회) / verify_password(신·구 형식 모두) / needs_rehash. 로그인 성공 시 구형이면 조용히 승급. change_password 는 해시를 SQL WHERE 로 비교하던 것을 코드 검증으로 교체(pbkdf2 는 SQL 비교 불가) |
| B1 평문 비번 | scripts/_db_config.py 로더 신설 → tracked 21파일(migrations 2 + scripts 19) 리터럴 제거. 값은 env → <repo>/.env(gitignore) → C:\dev\.secrets\pfs_db.env → EC2 env 순. 못 찾으면 예외 |
| B2 8791 | 기본 바인딩 0.0.0.0 → 127.0.0.1, /sync·/upload 전 경로에 토큰 요구(?t= 또는 헤더). 토큰 미설정이면 열지 않고 401 |
| C 응답 | 예외 문자열화 방어(비-str __str__ 에서 에러 응답이 붕괴하던 것) + RestResponse.status 매핑 추가만. 호출부 49개는 그대로 200 → 이 커밋으로 동작 안 바뀜 |
3. 배포·검증
- 커밋 = master
7ddfd50(A) ·6c4c1ef(B) ·d3fe28f(C) ·3955cbf(널가드) → deploy-live964e8f21회 push. - env 주입(테스트 → 운영 순):
PFS_SECRET_KEY(환경별 다른 값) ·PFS_AGENT_TOKEN(공용), 백업.bak-p0. - 로컬 상주 데몬 2종은 구버전으로 돌고 있었다 → 종료 후 재기동.
netstat로 8791 이0.0.0.0→127.0.0.1로 내려간 것 확인. - 검증: 자체검사 17 + E2E 13(테스트/운영 각각) + UI 회귀 9(테스트/운영 각각) 전부 PASS. 비로그인 API 401 · 데몬 토큰 없거나 틀리면 401 · 로그인 후 401 0건 · 로그인/재로그인 정상 · 틀린 비번 거부.
- 비번 승급 실측: 테스트에서 로그인한 계정 1건만
pbkdf2(111자)로 바뀌고 나머지 8건은 구형 유지 = 설계대로 점진.
4. 배포 중 발견한 것 (회귀 아님)
thousandSeparator널가드 누락 —amount가 null 이면toString()에서 TypeError 가 나고 DataTables 렌더가 통째로 멈춰 견적 목록이 빈 화면이 된다. 테스트 DB(월마감 백필분)에margin_total_amountnull 행이 있어서 드러났고 운영엔 그 데이터가 없어 안 보였을 뿐이다. 호출처 13곳 공통 유틸이라 여기서 한 번 막고, 수정이 사용자에게 닿도록pfs-utils.js참조에 캐시버스터를 붙였다(base.html·print.html). →PFS-D041- 진단 순서가 유효했다: 운영(미배포)을 대조군으로 같은 검증을 돌려 내 변경 탓이 아님을 먼저 갈랐다.
5. 사고 — 검증이 운영 큐를 건드림 (원복 완료)
/api/sticker/sync-poll은 pending 1건을 running 으로 claim 하는 엔드포인트다. 토큰 통과 확인용으로 운영에서 호출했더니 8일째 대기 중이던 요청(id=1, 2026-07-21)이 running 으로 바뀌었다.- 조건부 UPDATE(그 시각·그 상태인 행만)로
pending·started_at=NULL원상복구, 재조회로 확인. - 재발 방지 = 검증을 부작용 없는 경로로 교체(
sync-complete빈 body →id없으면 DB 미변경,{"ok":true}). 커밋master후속. 교훈: 검증 대상 엔드포인트가 상태를 바꾸는지 먼저 본다.
6. 남은 것
PFS-D002(fail() status 이관) = 파트별 점진 — 각 파트 디버깅 때 그 도메인만 전환.- TEST RDS 비번은 회전하지 않았다(페페 결정) → git 이력의 값은 여전히 유효하다. 회전하면 그때 무력화된다.
service/deploy-{live,test}.sh방치본 정리(PFS-D022)는 ops-secrets 트랙 잔여.