1. 서론: 공교육 전산망과 군 지휘소의 보이지 않는 위협, 열린 포트(Open Ports)
디지털 교과서 실습을 위해 40대의 학생 PC가 동시에 운영되는 초·중·고 정보실이나, 국방 지휘 통제 인트라넷에 연결된 데스크톱 환경에서는 "어떤 프로그램이 어떤 포트를 열고 있는가"를 파악하는 것이 보안 감사의 기본입니다.
많은 실무자들이 다음과 같은 현실적인 문제로 어려움을 겪습니다:
- 포트 충돌로 인한 수업 마비: 로컬 웹 서버(8080, 3000)나 파이썬 개발 런타임이 이전 프로세스의 비정상 종료로 포트를 물고 있어 신규 앱이 구동되지 않음.
- 비인가 원격 접속 백도어: 학생들이 몰래 설치한 프록시 소프트웨어나 악성 스크립트가 임의의 하이 포트(High Port)를 열고 대기함.
- 과도하게 무거운 상용 보안 에이전트: 수백 MB의 메모리를 먹는 외산 보안 패키지는 노후 PC의 CPU를 100% 점유하여 수업 자체를 불가능하게 만듦.
ZeliDesk의 시스템 진단 제품군 중 하나인 ZeliPort는 외부 종속성이나 무거운 감시 드라이버 없이, Windows 커널 표준 유틸리티(`netstat`)와 .NET 프로세스 관리자(`ProcessManager`)의 유기적 결합을 통해 초경량 실시간 포트 감사 엔진을 완성했습니다.
2. 커널 네트워크 테이블 질의: netstat -ano 무창(CreateNoWindow) 백그라운드 파이프 아키텍처
운영체제의 네트워크 소켓 바인딩 정보를 조회하는 가장 신뢰할 수 있는 방법은
Windows 커널의 TCP/IP 스택 드라이버(`tcpip.sys`)와 직접 통신하는 netstat -ano 명령어입니다:
-a: 모든 활성 연결 및 수신 대기(LISTENING) 포트 표시.-n: DNS 역조회 지연 없이 IP 주소와 포트 번호를 순수 숫자로 고속 출력.-o: 각 연결을 소유한 프로세스 식별자(PID) 출력.
PortScanner.cs는 사용자의 작업 화면에 검은색 콘솔 창(CMD)이 깜빡이는 현상을 0초 차단하기 위해
CreateNoWindow = true와 RedirectStandardOutput = true가 적용된
비동기 프로세스 파이프라인을 구축했습니다:
// ── ZeliPort/Services/PortScanner.cs ──
var psi = new ProcessStartInfo
{
FileName = "netstat",
Arguments = "-ano",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true // 🚫 콘솔 창 깜빡임 원천 차단
};
using var proc = Process.Start(psi);
if (proc == null) return ports;
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
이 파이프라인은 UI 스레드를 조금도 방해하지 않도록 Task.Run 백그라운드 워커 스레드에서 격리 실행되며,
수백 줄의 소켓 테이블을 0.03초 만에 인메모리 문자열 버퍼로 캡처합니다.
3. PID와 프로세스명의 원자적 결합: Process.GetProcesses() 인메모리 역매핑(Reverse Mapping)
netstat 명령어가 반환하는 정보의 치명적인 한계는 프로세스의 이름이 아니라
단순한 숫자 형태의 프로세스 식별자(PID, 예: 14280)만을 제공한다는 점입니다.
관리자나 교사는 PID 번호만 보고는 이것이 정당한 오피스 프로그램인지 악성코드인지 알 수 없습니다.
ZeliPort는 netstat을 실행하기 직전, Process.GetProcesses()를 호출하여
시스템에 현존하는 모든 프로세스의 `PID ➔ ProcessName` 인메모리 해시 매핑 딕셔너리를 사전 구축합니다:
var processMap = new Dictionary();
// 실시간 PID -> 프로세스 이름 역매핑 테이블 구축
var allProcs = Process.GetProcesses();
foreach (var p in allProcs)
{
try
{
processMap[p.Id] = p.ProcessName;
}
catch (System.ComponentModel.Win32Exception)
{
// 관리자 권한 프로세스 또는 시스템 커널 보호 프로세스
processMap[p.Id] = "System/Protected";
}
catch (System.InvalidOperationException)
{
// 찰나의 순간에 이미 종료된 프로세스
processMap[p.Id] = "Exited";
}
}
이 사전 역매핑 기법을 통해, netstat 출력 결과를 파싱할 때
개별 프로세스를 매번 Process.GetProcessById(pid)로 질의하는 $O(N)$ 병목을 제거하고,
$O(1)$ 해시 조회로 0.001ms 만에 정확한 실행 파일명을 결합해 냅니다.
4. 권한 상승 및 프로세스 종료 크래시 방어: Win32Exception 및 InvalidOperationException 샌드박스
윈도우 운영체제에는 `audiodg.exe`, `csrss.exe`, 보안 소프트웨어의 보호 프로세스(Protected Process Light, PPL)와 같이 일반 유저 모드 애플리케이션의 핸들 조회를 거부하는 특수 시스템 프로세스들이 상주합니다.
순진하게 p.ProcessName 프로퍼티에 접근하면 운영체제는 즉시
Win32Exception: 액세스가 거부되었습니다 에러를 던집니다.
또한 짧은 생명주기를 가진 백그라운드 작업은 순회 도중 종료되어 InvalidOperationException을 유발합니다.
ZeliPort는 이를 2단계 예외 샌드박스로 방어하여,
접근 권한이 없는 프로세스는 "System/Protected"로,
순회 중 증발한 프로세스는 "Exited"로 안전하게 라벨링하여
단 하나의 핸들 접근 예외로도 전체 스캔이 중단되지 않는 절대적인 안정성을 보장합니다.
5. 프로토콜 파싱 및 듀얼 스택 중복 제거: IPv4 0.0.0.0과 IPv6 [::]의 단일 진실 공급원(SSOT) 정규화
현대의 대다수 서버 소프트웨어(Node.js, Python FastAPI, Kestrel, Nginx)는
IPv4와 IPv6 요청을 모두 처리하기 위해 듀얼 스택(Dual Stack) 소켓을 엽니다.
이로 인해 netstat 출력에는 동일한 포트에 대해 두 줄의 레코드가 찍힙니다:
TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 5432
TCP [::]:8080 [::]:0 LISTENING 5432
이를 그대로 UI에 표시하면 동일한 포트가 2개씩 중복 나열되어 사용자에게 혼란을 줍니다. ZeliPort의 파서는 엄격한 듀얼 스택 중복 배제(Deduplication) 필터를 적용합니다:
// TCP 수신 대기 상태만 선별 (UDP는 상태 열 부재 감안)
if (protocol == "TCP" && state != "LISTENING") continue;
int port = 0;
int colonIndex = localAddress.LastIndexOf(':');
if (colonIndex > 0)
{
int.TryParse(localAddress.Substring(colonIndex + 1), out port);
}
if (port == 0) continue;
if (int.TryParse(parts[pidIndex], out int pid))
{
// 💡 0.0.0.0:8080과 [::]:8080 등 동일 포트/프로토콜의 중복 등록 원천 차단!
if (ports.Any(p => p.Port == port && p.Protocol == protocol)) continue;
string processName = processMap.TryGetValue(pid, out string name) ? name : "Unknown";
ports.Add(new PortItem
{
Protocol = protocol,
LocalAddress = localAddress,
Port = port,
State = state,
ProcessId = pid,
ProcessName = processName
});
}
이 정규화 로직을 통해 IPv4/IPv6 바인딩 여부와 관계없이 오직 포트 번호와 프로토콜 단위의 깔끔하고 직관적인 단일 진실 공급원(SSOT) 목록을 완성합니다.
6. 실시간 GUI 투영과 포트 정렬: WinUI 3 비동기 디스패치 및 오름차순 시각화 파이프라인
수집된 포트 목록은 번호 기준 오름차순(OrderBy(p => p.Port))으로 정렬되어 반환됩니다.
이를 통해 시스템 웰노운 포트(Well-Known Ports: 21, 22, 80, 443)부터
등록 포트(Registered: 3000, 5000, 8080) 및 동적/사설 포트(Dynamic: 49152~)가
일목요연하게 계층화됩니다:
| 포트 번호 (Port) | 프로토콜 (Protocol) | 프로세스명 (Process Name) | PID | 보안 감사 판정 (Audit Status) |
|---|---|---|---|---|
80 / 443 |
TCP | System (HTTP.sys) |
4 | 정상 Windows 공식 웹 서비스 바인딩 |
5001 |
TCP | ZeliDesk.Server |
11420 | 800GB 온디바이스 AI 모델 허브 스트리밍 엔드포인트 |
8080 |
TCP | node.exe |
8392 | 학생 코딩 실습 로컬 웹 서버 (정상 인가) |
65432 |
TCP | svchost_fake.exe |
19284 | ⚠️ 비인가 하이 포트 대기 — 즉각적인 침해 차단 대상! |
7. 실무 응용 시나리오: 교내 AI 웹 서버 포트 충돌 해결 및 군 전산망 비인가 백도어 0초 탐지
ZeliPort의 가치는 실제 교육 및 국방 현장의 긴급 장애 상황에서 입증됩니다:
파이썬 AI 실습 중 이전 세션이 종료되지 않아 5000번 포트가 묶였을 때, 재부팅할 필요 없이 ZeliPort를 켜서 5000번 포트를 잡고 있는 좀비 `python.exe`의 PID를 즉시 확인하고 ZeliProc이나 작업 관리자로 원클릭 정리하여 10초 만에 수업을 정상화합니다.
USB나 외장 매체를 통해 무단 반입된 외부 P2P/원격 제어 툴이 백그라운드에서 포트를 개방했을 때, ZeliPort를 실행하여 평소에 없던 의심스러운 하이 포트와 프로세스명을 즉시 식별하고 보안 담당관에게 증빙 로그로 보고할 수 있습니다.
8. 결론: 가장 가볍고 안전한 온디바이스 네트워크 보안 진단 도구의 기준
진정한 보안 유틸리티는 스스로가 시스템의 부담이 되어서는 안 됩니다. 무거운 상주 데몬을 요구하거나 복잡한 드라이버를 설치해야만 포트를 확인할 수 있다면, 그 자체가 노후 데스크톱에는 또 다른 장애 요인이 됩니다.
ZeliPort는 단 95줄의 순수 C# 아키텍처만으로 커널 파이프 질의, 인메모리 프로세스 역매핑, 권한 예외 샌드박싱, 그리고 듀얼 스택 정규화를 완벽하게 조화시켰습니다.
공교육 교실의 안정적인 코딩 실습 환경부터 국방 전산망의 철통같은 소켓 감사까지, ZeliPort는 단 1초의 지연도 없는 무결점 온디바이스 네트워크 수호자로서 ZeliDesk 생태계의 든든한 방패가 되어주고 있습니다.