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, 무자격증명 요청이 스로틀에 안 잡히는 것, 성공 시
카운터 초기화 포함.