← 목록
기타 2026-07-27 6KB 읽기 7분

크라우니클라우드 실인증 구현 (P0-③) — 라이브 cloud:9611

개요

무비번 capability-token(=owner 문자열) 모델을 자체 서명 세션토큰 + 비밀번호 자격증명으로 승격. 하위호환 브리지(Bearer 우선, X-Crowny-Owner 폴백 유지)로 무중단 이행.
  • 결정A = 자체 서명 세션토큰 (auth.crowny.org 미통합 — 과거 P0 6건 이력이라 결합 회피).
  • 결정B = 하위호환 브리지 (기존 사용자 안 깨짐).
  • 2FA·실 HMAC 하드닝은 후속(이번 범위 제외).

서버 (/Users/ef/crowny-services/서비스서버.한선, 컴파일→서비스서버.toau)

신규 엔드포인트

  • POST /api/auth/register {owner,password}{ok,owner}. owner=소유자유효 강제(8~100 [a-zA-Z0-9_-]), password≥8, 중복=409.
  • POST /api/auth/login {owner,password}{ok,token,exp}. 실패 전부 401 invalid credentials(존재여부 비노출).
  • POST /api/auth/logout-all (인증확정 필요) → auth파일 ver+1 → 기존 세션 전부 무효.

시크릿 / 해시 방식

  • 서버 시크릿 = data/auth/.secret (없으면 1회 생성: 현재시각()|랜덤HEX(64)|무작위(0,2e9)×2|포트 → SHA256 64hex, chmod 600). 재기동 간 안정.
  • 비번 저장 = data/auth/<owner>.json {salt,hash,ver}. salt=랜덤HEX(32), hash=반복 SHA256(salt+비번) 4096회(PBKDF2 유사).
  • ⚠️ 반복수: 설계 "예 10000"에서 4096으로 조정 — 실측상 hanseonc VM은 SHA256 호출당 문자열핸들 1개 생성(GC 대상). 10000반복은 로그인 버스트 시 STR풀 90% 조기경고 유발. 4096은 30연속 로그인 0.43s·경고 0건.
  • 세션토큰 = owner.exp.ver.sig. exp=현재시각()+604800(7일). sig=SHA256(시크릿|owner|exp|ver|시크릿) — 시크릿 앞뒤 봉투로 length-extension 방어(진짜 HMAC은 후속).
  • 무작위 함정 회피: 16진 니블은 무작위(0,16) 2인자 직접(feedback_인증라이브러리 P0 — 무작위() 0인자=[0,32768) 큰정수 클램프 고정값 방지).
  • 인증확정(원시) — 통합 함수 (하위호환 브리지)

    1. Authorization: Bearer <owner.exp.ver.sig> 파싱(점3개 4분할) → exp 미경과 + ver 일치(auth파일 재조회) + sig 재계산 일치 → owner 반환.
    2. 무효/부재면 소유자추출(X-Crowny-Owner 헤더) 폴백 → 유효하면 owner 반환.
    3. 둘 다 없으면 "" → 호출부 소유자유효("")=거짓 → 401.
    • JWT(점2개=3분할) 위임돼도 4분할 실패 → owner 폴백. 무해.

    교체 핸들러 (소유자추출 → 인증확정, 9지점)

    store · anchor · merge · quota · access · share(POST) · share(DELETE) · files · zip.
    • blob 디스패처는 owner를 URL 경로에서 취함(헤더 아님) → 교체 대상 아님(불변).
    • CORS(CORS204) Access-Control-Allow-HeadersAuthorization 추가.

    소비처 (/Users/ef/crowny-ai/engine/cloud-connect.js)

    • 신규: cloudLogin(owner,password)(토큰 발급+owner→토큰 캐시), cloudRegister, cloudBearerFor(Bearer 결정).
    • proxyToCloud: 들어온 Authorization Bearer 우선 위임 / 없으면 캐시 세션토큰 주입 / X-Crowny-Owner 항상 병행(폴백). 토큰 없거나 무효여도 cloud가 owner 폴백 → 기존 동작 유지.
    • crowny-ai 재시작 불필요(백워드호환 — 다음 재시작 시 자동 적용).
    • 한선씨 동반: /Users/ef/crowny-ai/클라우드연결.한선에 브리지 판정 로직(토큰형식판정·세션만료판정·Bearer선택) 추가, 자가검증 7/7 PASS.

    index.html — 무수정 (판단)

    crowny-ai·chansong.crowny.org public/cloud/index.html byte-identical 유지(양쪽 무수정). 로그인 UI 추가는 복잡+양쪽 동기 필요 → 브리지 폴백으로 기존 동작 그대로. 로그인 UI는 후속.

    컴파일 / 재기동

    • STRICT 컴파일 신규경고 0 (58177 큐브). 서비스서버.toau 배포(1628956B).
    • cloud 단독 재기동: 9611 리스너(구 PID 11638) kill → ROOT에서 SERVICE=cloud PORT=9611 디태치 재기동. 신 PID 67694. manage.sh 미사용, 9611 외 미접촉. 데몬 자가치유 틱 후에도 단일 리스너 확인(중복 0).

    검증 (실측 원문)

    1. health 200.
    2. register(testowner01)→login→토큰 testowner01.1785713047.1.82f6…. Bearer만으로(owner 헤더 없이) store=200 quota=200, store POST/GET 왕복 {"hello":"world"}.
    3. 하위호환: Bearer 없이 X-Crowny-Owner만 → store=200 quota=200.
    4. 잘못된 비번=401 · 없는 owner=401(동일 invalid credentials) · 위조 sig=401 · 만료 exp=401 · 위조 Bearer+유효 owner헤더=200(브리지 폴백). RCE 화이트리스트: 셸메타 owner register=400·헤더=401, /tmp/pwned 미생성.
    5. logout-all→구 토큰 401(ver 불일치)→재login ver=2 토큰 200.
    6. 회귀: merge LWW {ok,items}·share note POST/GET·blob upload(sha256 반환)·files 정상. index.html byte-identical.
    7. 이웃 생존: 9852=200, 9606/9607/9608=응답(404=라우트無, 리스닝 생존). 라이브 9611 재검증 health=200·login/register GET=405.
    라이브 최종: register→login→Bearer store=200 quota=200, legacy owner=200 (production 9611).

    관련 파일

    • /Users/ef/crowny-services/서비스서버.한선 (인증 블록 + 라우팅 + 인증확정 교체)
    • /Users/ef/crowny-services/서비스서버.toau (배포본, .bak-실인증 백업)
    • /Users/ef/crowny-ai/engine/cloud-connect.js (+.bak-실인증) · /Users/ef/crowny-ai/클라우드연결.한선
    • 시크릿: /Users/ef/crowny-services/data/auth/.secret (chmod 600)

    잔여 이슈 (후속)

    • 실 HMAC-SHA256(현재는 봉투 MAC 근사) + scrypt/bcrypt급 스트레치(현재 4096 반복 SHA256).
    • 2FA(TOTP).
    • 세션토큰 상수시간 비교(현재 문자열 ==).
    • cloud/index.html 로그인 UI + widget-cloud.js login 흐름.
    • 3단계: X-Crowny-Owner 단독 인증 제거(폴백 사용률 0 확인 후).