No description
Find a file
changukyu 278372d171 fix: SSRF DNS-rebinding TOCTOU 차단 + 실패 인증 스로틀
7/11 체크리스트에서 미착수로 남아 있던 보안 2건. 나머지 미체크 항목은 코드와
대조한 결과 이미 수정돼 있었거나(6건) 근거가 기재된 명시적 연기다.

SSRF DNS-rebinding (store_remote_fetch.py)
  _assert_public_http_url 이 호스트를 해석해 통과 여부를 정하고 나면,
  http.client 가 소켓을 열 때 같은 이름을 한 번 더 해석했다. 리바인딩
  호스트는 첫 조회에 공인 주소를, 두 번째에 127.0.0.1 을 답하면 그만이었다.
  _guarded_create_connection 이 getaddrinfo 를 1회만 수행하고, 그 답변의
  주소를 전부 검증한 뒤 그중 하나로만 연결한다 — 검사한 주소와 실제 다이얼
  하는 주소가 갈라지지 않는다. 답변에 내부 주소가 하나라도 섞이면 거부한다
  (공인+내부 혼합이 리바인딩 패턴 자체이고, connect 가 어느 항목에 닿을지는
  예측 대상이 아니다). HTTPConnection._create_connection 을 갈아끼우는
  방식이라 connect() 의 나머지(TCP_NODELAY, 터널링)와 HTTPS 의 TLS 검증
  (self.host 기준)은 그대로 유지된다.

실패 인증 스로틀 (auth_rate_limit.py)
  COPYRIGHTER_AUTH_TOKEN 이 데이터 라우트의 유일한 게이트인데 틀린 토큰의
  비용이 요청 1회였다. 클라이언트 주소별 고정 윈도우 10회/60초, 초과 시
  429 + Retry-After. 성공하면 카운터를 비운다.
  자격증명을 실제로 제시하고 틀린 경우만 센다 — 콘솔은 토큰 입력 전에도 API
  를 여러 건 호출하므로, 그 401 들을 세면 정직한 페이지 로드 두 번으로
  운영자가 잠긴다. Origin 거부는 유효 세션의 CSRF 검사 실패지 추측이 아니라
  세지 않는다. 추적 테이블은 1024 클라이언트로 상한(만료분 우선 회수).

테스트 26건 추가. 리바인딩 회귀 재현(사전검사는 통과시키고 connect 에서 거부),
스로틀의 429/Retry-After, 무자격증명 요청이 스로틀에 안 잡히는 것, 성공 시
카운터 초기화 포함.
2026-08-08 09:49:31 +09:00
docs docs: INDEX 에 실렌더 검증 기록 2026-07-26 00:30:24 +09:00
src/rights_filter fix: SSRF DNS-rebinding TOCTOU 차단 + 실패 인증 스로틀 2026-08-08 09:49:31 +09:00
tests fix: SSRF DNS-rebinding TOCTOU 차단 + 실패 인증 스로틀 2026-08-08 09:49:31 +09:00
web/operator-gui refactor: app.js 5,428줄을 관심사별 app-*.js 15개로 분할 2026-08-08 09:48:52 +09:00
.env.example fix: 형식 예시 반향 차단, 기본 모델을 실측으로 qwen2.5:7b 로 확정 2026-07-25 23:48:23 +09:00
.gitattributes chore: add .gitattributes to enforce LF line endings 2026-06-22 11:22:23 +09:00
.gitignore feat: 실사용 투입 전 T0 스탬프 4종 + 임베딩 정책 개정 2026-07-25 23:08:19 +09:00
package.json chore: initial commit of copyrighter (rights_filter) 2026-06-09 09:50:31 +09:00
pytest.ini chore: 단일 verify 게이트 신설 (pytest.ini + ruff.toml + verify.ps1) 2026-08-08 09:47:57 +09:00
README.md docs: 2026-07-24 review report, implementation checklist, spec revision 2026-07-24 14:18:27 +09:00
requirements-dev.txt chore: 단일 verify 게이트 신설 (pytest.ini + ruff.toml + verify.ps1) 2026-08-08 09:47:57 +09:00
requirements.txt chore: pin runtime dependencies for offline air-gapped install 2026-06-20 18:19:08 +09:00
ruff.toml chore: 단일 verify 게이트 신설 (pytest.ini + ruff.toml + verify.ps1) 2026-08-08 09:47:57 +09:00
run_copyrighter_server.py fix: 운영자 콘솔 실렌더 검증에서 드러난 결함 5종 2026-07-26 00:29:54 +09:00
verify.ps1 chore: 단일 verify 게이트 신설 (pytest.ini + ruff.toml + verify.ps1) 2026-08-08 09:47:57 +09:00

POSA Copyrighter

이미지 저작권 위험을 자동 분석하고, 운영자가 콘솔에서 근거를 확인해 승인 / 보류 / 반려를 판정하는 폐쇄망(air-gapped) 운영 도구입니다.

  • 분석 서버: 제출 이미지를 분석해 위험도·근거를 산출하고 SQLite에 저장
  • 운영자 콘솔: 심사 큐, 근거 검토, 판정, 지식 DB, 감사 로그를 제공하는 단일 페이지 웹 GUI
  • 외부 근거 검색: Naver 검색, Google Vision/Custom Search, 로컬 LLM(Ollama) 연동(선택)

요구 사항

  • Python 3.13
  • 런타임 서드파티 의존성은 이미지 처리 라이브러리뿐입니다(지연 로딩): numpy, opencv-python-headless, pillow

폐쇄망(air-gapped) 원칙: 모든 의존성·자산은 빌드/스테이징 머신에서 미리 받아 오프라인 휠로 설치합니다. 대상 서버는 설치·실행 시 인터넷에 접근하지 않습니다. 자세한 절차는 docs/operations/offline-install.md를 참고하세요.

설치

# 개발 머신 (온라인) — 의존성 설치
pip install -r requirements.txt          # 런타임
pip install -r requirements-dev.txt      # 테스트 포함

# 폐쇄망 대상 — 오프라인 휠로 설치 (예시)
pip install --no-index --find-links wheelhouse -r requirements.txt

.env.example를 복사해 .env를 만들고 필요한 값(인증 토큰, 검색 API 키 등)을 채웁니다. 키를 비워 두면 해당 외부 검색은 자동으로 비활성화됩니다.

cp .env.example .env

실행

python run_copyrighter_server.py
# 옵션은 런처에 그대로 전달됩니다
python run_copyrighter_server.py --host 127.0.0.1 --port 9500

python -m rights_filter.server 로 직접 실행하려면 src/ 가 import 경로에 있어야 합니다 (PYTHONPATH=src, Windows PowerShell 은 $env:PYTHONPATH="src"). 런처는 이 경로 설정과 작업 디렉터리 고정을 대신 해 주므로 run_copyrighter_server.py 사용을 권장합니다.

주요 옵션: --host, --port, --db(SQLite 경로), --images(제출 이미지 폴더), --static(운영자 GUI 경로), --env(.env 경로).

기본값으로 실행하면 http://127.0.0.1:9500 에서 운영자 콘솔이 열립니다.

보안: COPYRIGHTER_AUTH_TOKEN이 비어 있으면 데이터 라우트가 인증 없이 열립니다. 단일 호스트 개발 환경 외에는 반드시 토큰을 설정하세요.

프로젝트 구조

src/rights_filter/      분석·서버·통합·도메인 로직 (Python)
  server/               http.server 기반 API + 정적 파일 서빙, SQLite 저장소
  analysis/             이미지 분석·위험도 산출
  integrations/         Naver / Google / LLM 어댑터
web/operator-gui/       운영자 콘솔 (정적 SPA: index.html, app.js, styles.css)
tests/                  pytest 테스트
  operator_gui/         운영자 GUI 정적 검증 + Playwright E2E
docs/                   기획·설계·운영 문서

테스트

# 전체
python -m pytest

# 운영자 GUI E2E (Playwright)
playwright install chromium      # 빌드 머신에서 1회 — 브라우저 바이너리는 오프라인 번들에 포함
python -m pytest tests/operator_gui/
  • 브라우저(E2E) 테스트는 Playwright/Chromium이 없으면 자동으로 건너뜁니다(importorskip + graceful skip).
  • 운영자 워크벤치는 tests/operator_gui/pages/의 Page Object(OperatorWorkbench)와 conftest.py의 공용 픽스처를 사용합니다.

문서