프로젝트 / 비비드인덱스

리팩토링

2026.02.14 3분 읽기

리팩토링과 삽질 — ModSecurity와의 전쟁, 그리고 아키텍처 재설계

2026년 2월 4일 — 하루 종일 400 Bad Request와 싸웠다. 원인은 예상치 못한 곳에 있었다.


그날의 시작

2월 4일, 아침부터 코드를 리팩토링하기로 했다. BTC와 ALT 두 개의 시스템이 각각 다른 DB 테이블, 다른 API 구조, 다른 워크플로우로 돌아가고 있었고, 이대로는 새 전략을 추가할 때마다 모든 걸 처음부터 만들어야 했다.

목표는 명확했다:

간단할 줄 알았다. 전혀 아니었다.


400 Bad Request의 늪

BTC API를 /model/api/ 경로에서 다른 곳으로 옮기는 과정에서 문제가 시작됐다. n8n에서 API를 호출하면 ERROR: Request failed with status code 400 메시지만 반복됐다.

PHP 코드는 아예 실행되지 않았다. echo "hello"; 한 줄짜리 파일도 400을 뱉었다. PHP 문법 오류도 아니었다. 로컬에서는 잘 되는데 서버에서만 안 됐다.

원인 찾기 — 삽질의 기록


범인: ModSecurity (닷홈 웹 방화벽)

닷홈 공유 호스팅의 ModSecurity(웹 방화벽)가 특정 패턴을 차단하고 있었다.

차단 패턴 예시 차단 이유
특정 경로명 /model/api/*.php 의심스러운 시스템 경로명
비200 응답 http_response_code(400) 악성 에러 페이지 생성 의심
경로 탐색 ../../config.php 디렉토리 트래버설 공격 방어
난독화 패턴 base64_decode() 악성 스크립트 실행 의심

http_response_code(400)을 설정하는 PHP 파일을 ModSecurity가 "이 파일은 400 에러를 의도적으로 만드는 악성 코드"로 판단해서 파일 자체를 차단한 것이다. PHP가 실행되기도 전에 Apache 레벨에서 요청이 거부됐으니, 아무리 코드를 고쳐도 소용이 없었던 것이다.


해결 원칙: 닷홈 생존 가이드

이 삽질에서 얻은 교훈을 바탕으로 비비드인덱스의 배포 원칙을 정리했다.

  1. 경로명 주의: /model/, /admin/ 같은 민감한 이름은 절대 피할 것.
  2. 항상 HTTP 200: 에러 응답도 HTTP 200으로 보내고, JSON body에서 success: false로 구분할 것.
  3. 절대 경로 사용: ../../ 대신 $_SERVER['DOCUMENT_ROOT']를 활용할 것.
  4. 난독화 금지: base64_encode/decode 사용을 자제할 것.
  5. POST 테스트 필수: GET은 통과해도 POST만 차단되는 경우가 많으니 반드시 확인.


같은 날: 멀티 전략 아키텍처 설계

삽질을 끝내고 나서야 원래 하려던 멀티 전략 아키텍처 설계에 착수했다.

현재 구조의 문제점

BTC와 ALT가 각각 전용 테이블과 로직을 가져서 새 전략을 추가할 때마다 코드 중복이 심하고 성과 비교가 불가능했다.

설계한 새 구조 (통합 DB)

핵심은 WHERE strategy = ?만으로 모든 데이터를 필터링할 수 있게 만드는 것이다. 이제 SQL 한 줄로 모든 전략의 승률을 비교할 수 있다.


바이낸스 타임스탬프 동기화 에러

리팩토링 마무리 단계에서 바이낸스 API가 타임스탬프 에러를 뱉었다. n8n 서버와 바이낸스 서버의 시간이 미세하게 어긋난 것이 원인이었다.

해결: API 요청 직전에 바이낸스 서버 시간을 먼저 조회하고, 그 시간을 기준으로 타임스탬프를 설정하도록 수정했다.


하루의 교훈

EP.06 | 2026년 2월 4일

Vivid Index 개발기

비비드인덱스 글 목록

← 프로젝트로 이동
비트인덱스 전략 수정 2026.02.24 성적과 학습 시스템 2026.02.19 테스트 2026.02.14 리팩토링 2026.02.14 알트코인 전략 2026.02.14 깃 커밋 2026.01.30 글로벌 확장 계획 2026.01.26 대시보드 구성 2026.01.25 플랫폼 전환 2026.01.12 시작 2026.01.05