← ~/notes · 3 min read

허니팟 대시보드 개선기 — 버그 3개 잡고 디자인 갈아엎은 기록

Alpine.js silent failure, CSS overflow 함정, iptables 권한 문제 — 허니팟 SOC 대시보드를 고치면서 만난 것들.

목차
  1. 버그 1 — 버튼 5개에 라벨이 없다
  2. 버그 2 — 차단 IP 드롭다운이 잘린다
  3. 버그 3 — /api/blocked-ips 500 에러
  4. iptables 자동 차단 검증
  5. 디자인 전면 개편
  6. 새로 추가한 기능
  7. 차단 IP 목록 모달
  8. 24시간 누적 수치

허니팟 SOC 구축기를 쓴 날, 대시보드에서 버그 3개를 발견했다. 고치는 김에 디자인까지 갈아엎었다.


버그 1 — 버튼 5개에 라벨이 없다

시간 범위를 선택하는 버튼 5개(1시간 / 6시간 / 24시간 / 7일 / 30일)가 전부 빈 칸으로 떴다.

Alpine.js의 x-text로 라벨을 동적으로 바인딩하는 코드였는데:

x-text="({1h:'1시간', 6h:'6시간', '24h':'24시간', '7d':'7일', '30d':'30일'})[r]||r"

1h와 6h에 따옴표가 없다. JavaScript 객체 리터럴에서 숫자로 시작하는 키는 반드시 따옴표로 감싸야 한다. 그렇지 않으면 SyntaxError가 발생하고, Alpine.js는 이걸 조용히 삼켜버려서 바인딩 전체가 아무 출력 없이 실패한다.

<!-- 수정 후 -->
x-text="({'1h':'1시간','6h':'6시간','24h':'24시간','7d':'7일','30d':'30일'})[r]||r"

이게 교과서에 나오는 실수인데 Alpine.js의 silent failure 때문에 디버깅이 한참 걸렸다.


버그 2 — 차단 IP 드롭다운이 잘린다

차단 IP 목록 버튼을 눌렀을 때 드롭다운 메뉴가 아래로 내려오지 않고 보이지 않았다.

원인은 CSS overflow 연쇄 효과다.

컨트롤 바에 overflow-x: auto를 걸어두면 CSS 사양에 따라 overflow-y도 자동으로 auto가 된다. 컨테이너 높이가 46px인 상태에서 overflow-y: auto가 걸리면, 아래로 펼쳐지는 절대 위치 드롭다운은 전부 클리핑된다.

.ctrl-inner (overflow-x: auto → overflow-y: auto 자동 적용)
    └── 높이 46px
         └── .dropdown (position: absolute, top: 100%)
              → 클리핑되어 안 보임

해결책은 간단했다. 드롭다운 버튼을 overflow가 걸린 컨테이너 밖으로 꺼냈다.

<!-- 변경 전: overflow-x 컨테이너 안 -->
<div class="ctrl-inner">
  ...모든 버튼...
</div>

<!-- 변경 후: 오른쪽에 별도 영역 -->
<div class="ctrl-inner">
  <!-- 범위 버튼, 검색, CSV -->
</div>
<div class="ctrl-right">
  <!-- 차단 IP 목록, 리포트 전송 -->
</div>

버그 3 — /api/blocked-ips 500 에러

차단 IP 목록을 가져오는 API가 500을 뱉었다. 쿼리를 보니:

SELECT ip, reason, blocked_at
FROM blocked_ips
WHERE active = 1
ORDER BY blocked_at DESC

blocked_ips 테이블 컬럼 이름이 active가 아니라 auto였다. 스키마를 안 보고 기억으로 짰다가 생긴 실수. WHERE 절을 제거해서 전체를 조회하도록 수정했다.


iptables 자동 차단 검증

공격 탐지 → iptables 자동 차단 파이프라인이 실제로 작동하는지 확인했다.

테스트 이벤트를 직접 주입해서 흐름을 추적했다:

# Cowrie 로그에 테스트 이벤트 주입
echo '{"eventid":"cowrie.command.input","src_ip":"1.2.3.4","input":"xmrig --url stratum+tcp://pool.example.com"}' \
  >> /opt/honeypot/cowrie/var/log/cowrie/cowrie.json

6초 안에:

  1. aggregator.py가 로그 감지
  2. 크립토 마이너 시그니처 매칭
  3. iptables -I INPUT 1 -s 1.2.3.4 -j DROP 실행
  4. /etc/iptables/rules.v4 저장
  5. Discord 알림 전송

모두 정상 동작했다. systemd 서비스에서 iptables를 실행하려면 AmbientCapabilities=CAP_NET_ADMIN이 필요한데, 이걸 서비스 파일에 추가하면서 해결했던 부분이다.


디자인 전면 개편

기존 대시보드는 파란 격자 배경에 형광 글로우 효과였다. 장난감 같다는 생각이 들어서 전부 갈아엎었다.

바뀐 것들:

항목전후
배경#1e2d42 + 파란 격자 body::before#0d1117 (GitHub 다크)
카드 배경#253552#161b27
테두리rgba(148,163,184,0.22)rgba(255,255,255,0.07)
수치 색상각 카드마다 형광색전부 var(--text) 흰색 (아이콘이 색 담당)
글로우box-shadow 형광 효과 다수제거
컬러 관리33개 하드코딩 hexCSS 변수 (--bg, --card, --accent 등)

로고도 바꿨다. HONEYPOT SOC LAB-IT.NET · 위협인텔리전스 텍스트 나열에서 크로스헤어 SVG 아이콘 + HoneyPot 그라디언트 텍스트 + SOC 모노스페이스 배지 구조로.


새로 추가한 기능

차단 IP 목록 모달

기존에는 차단 IP가 드롭다운 메뉴에 나열되는 구조였다. 이걸 전체 화면 모달로 바꾸고:

  • IP, 차단 사유, 차단 일시 테이블 표시
  • iptables 형식 다운로드: iptables -I INPUT 1 -s {IP} -j DROP 스크립트
  • nginx 형식 다운로드: deny {IP}; 블록

다른 서버에 차단 목록을 적용할 때 바로 쓸 수 있다.


24시간 누적 수치

작업 시점 기준:

항목수치
누적 전체59,637건
24시간 이벤트2,869건
고유 공격자 IP65개
자동 차단 IP16개

상위 출처는 프랑스(2,197건)였다. AbuseIPDB 점수 0%짜리 IP가 하루에 2,000건 이상을 때리고 있다.


버그 수정은 그냥 고치면 끝이지만, 원인을 파악하는 과정이 재밌다. CSS overflow 연쇄 효과나 Alpine.js silent failure는 문서에 분명히 나와 있는 내용인데 실제로 만나면 한참 헤맨다. 기록해두는 이유가 이거다.