📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 87편
이전 글: 86. 내부망 주요 Port · 다음 글: 88. 위험 Port
참고(리눅스 시스템 기초): Firewalld 이해 — zone·service 개념과 기본 명령
01편부터 21편까지 서비스별로 포트를 살펴봤습니다. 이제 이것을 정책의 언어로 바꿀 차례입니다. 관제 요원이 방화벽 로그에서 "외부 IP → 내부 서버 445 허용"이라는 한 줄을 봤을 때, 이것이 정책 위반인지 즉시 판단할 수 있어야 합니다. 그러려면 "어떤 포트가 어디까지 열려도 되는가"라는 기준이 머릿속에 있어야 합니다.
외부 노출 사고의 상당수는 새로운 취약점보다 열려 있으면 안 되는 포트가 열려 있는 것에서 시작한다는 점이 여러 보안 보고서에서 반복적으로 지적됩니다. RDP(15편), SMB(14편), DB(19편)가 대표적입니다.
이 글은 포트를 세 가지로 분류하고, 인바운드뿐 아니라 아웃바운드까지 포함한 포트 정책의 기준을 정리합니다. 방화벽 제품별 규칙 작성과 IDS 연동은 06. 방화벽 · IDS/IPS 분석 시리즈에서 다룹니다.

그림 1. 인터넷·DMZ·내부망 구역에 따라 열어도 되는 포트가 다릅니다
| 원칙 | 의미 |
|---|---|
| 기본 거부(Default Deny) | 명시적으로 허용한 것 외에는 모두 차단 |
| 최소 노출 | 서비스에 꼭 필요한 포트만, 꼭 필요한 출발지에만 |
| 관리 경로 분리 | SSH·RDP·관리 콘솔은 VPN·배스천(점프) 서버·관리망을 통해서만 |
| 출발지 한정 | "모두 허용"이 아니라 "특정 서버·대역 허용" |
| 양방향 통제 | 인바운드뿐 아니라 서버의 아웃바운드도 필요한 것만 |
| 문서화·주기 점검 | 허용 규칙마다 사유·담당자·만료일을 기록 |
| 분류 | 포트 예 | 조건 |
|---|---|---|
| 외부 공개 가능 | 80·443(웹), 25(메일 수신 서버), 53(외부용 권한 DNS 서버) | 해당 역할의 서버에만, DMZ에 배치 |
| 내부 전용 | 53(내부 DNS), 123(NTP), 88·389·636·3268(인증), 445(파일 공유), 514(Syslog), 161(SNMP, 관리망), DB 포트(앱 서버에서만), 22(관리망·배스천에서만) | 내부 대역 또는 특정 서버로 출발지 한정 |
| 외부 노출 금지 | 23(Telnet), 21(FTP), 69(TFTP), 111(rpcbind), 135·137~139(RPC·NetBIOS), 445(SMB), 3389(RDP), 161(SNMP), 3306·1433·5432·1521(DB), 6379(Redis), 9200(Elasticsearch), 11211(Memcached), 2375(Docker API 평문), 5900(VNC) | 인터넷에 직접 노출하지 않음. 원격 접근이 필요하면 VPN 경유 |
22(SSH)와 3389(RDP)는 "관리 포트"로, 인터넷에 직접 노출하기보다 VPN·배스천 뒤에 두는 것이 일반적 권고입니다. 외부 공개가 불가피하다면 출발지 제한, 키 기반 인증, 다중 인증 등 보완 통제가 필요합니다(SSH는 리눅스 시스템 기초 시리즈 13. SSH 보안 설정 참고).
서버가 인터넷으로 나가는 통신도 정책 대상입니다. 21편의 C2 통신, 19편의 DB 서버 외부 송신은 모두 아웃바운드에서 보입니다.
| 트래픽 | 권장 기준 |
|---|---|
| DNS (53) | 내부 DNS 서버로만. 일반 서버·PC의 외부 DNS 직접 질의는 차단 또는 탐지 |
| NTP (123) | 내부 NTP 서버로만(17편) |
| SMTP (25) | 메일 서버만 외부 25 허용. 일반 PC의 외부 25 연결은 스팸 발송 감염 의심 |
| 웹 (80·443) | 프록시 경유 원칙. 서버는 업데이트 저장소 등 필요한 목적지로 제한 |
| SMB (445) | 외부로 나가는 445는 차단(자격 증명 유출 위험) |
| 그 외 임의 포트 | 기본 차단, 필요 시 목적지·포트 단위 예외 |
일반적인 3계층 구조에서 포트 정책이 적용되는 위치입니다.
인터넷
│ 허용: 443(웹), 25(메일 서버), 53(외부 DNS) / 나머지 인바운드 차단
↓
[경계 방화벽]
↓
┌──────── DMZ ────────┐
│ 웹 서버 메일 서버 │ ── 허용: 웹 → 앱 서버 8080만
└─────────┬───────────┘
↓
[내부 방화벽]
↓
┌──────── 내부 서버망 ────────┐
│ 앱 서버 → DB 서버 3306 │ ← DB는 앱 서버 출발지만 허용
│ DC(88·389) · DNS · NTP │ ← 내부 대역만
└─────────┬───────────────────┘
↑
[관리망 / 배스천] ── SSH 22 · RDP 3389 · SNMP 161 은 여기서만
↑
[사용자망 PC] ── 인터넷 443은 프록시 경유 / 서버 관리 포트 직접 접근 불가
각 단계에서 "이 포트가 이 구간을 넘어가도 되는가"를 판단하는 것이 포트 정책입니다. 그리고 호스트 방화벽(firewalld·ufw) 은 네트워크 방화벽이 잘못 설정됐을 때를 대비한 마지막 층입니다.
실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu). 인터페이스 ens33, 관리 대역 192.168.10.0/24는 예시입니다.
⚠️ SSH로 원격 접속한 상태에서 방화벽을 바꾸면 스스로 접속이 끊길 수 있습니다. VM 콘솔에서 작업하거나, SSH 허용 규칙을 먼저 추가한 뒤 기본 정책을 바꿉니다.
sudo firewall-cmd --state
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all
Rocky의 기본 public zone에는 보통 cockpit, dhcpv6-client, ssh 서비스가 허용되어 있습니다. 사용하지 않는 서비스는 제거합니다.
# 1) 관리 대역을 trusted가 아닌 internal zone에 등록하고 SSH 허용
sudo firewall-cmd --permanent --zone=internal --add-source=192.168.10.0/24
sudo firewall-cmd --permanent --zone=internal --add-service=ssh
# 2) public zone에서는 SSH·cockpit 제거
sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --permanent --zone=public --remove-service=cockpit
sudo firewall-cmd --reload
sudo firewall-cmd --zone=internal --list-all
sudo firewall-cmd --zone=public --list-all
internal zone에는 기본적으로 ssh 외에도 몇몇 서비스가 허용되어 있으므로 --zone=internal --list-all로 확인하고 불필요한 서비스는 --remove-service로 제거합니다. firewalld는 패킷의 출발지가 zone에 등록된 source와 일치하면 그 zone의 규칙을 적용하고, 그렇지 않으면 인터페이스에 연결된 zone(예: public)의 규칙을 적용합니다.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose
Docker를 사용하는 호스트에서는 컨테이너 게시 포트(-p)가 Docker가 추가하는 iptables 규칙으로 처리되어 ufw 규칙을 우회할 수 있다는 점이 알려져 있습니다. Docker 호스트는 ss와 외부 도달 테스트로 반드시 교차 확인합니다.
sudo ss -tulnH | awk '{print $1, $5}' | sort -u
LISTEN 목록에는 있지만 방화벽 허용 목록에 없는 포트는 "지금은 막혀 있지만 방화벽 설정 실수 한 번에 노출될 포트"입니다. 불필요하다면 서비스 자체를 중지합니다.
📷 [실습 화면 삽입] 변경 전후
firewall-cmd --zone=public --list-all비교 (Rocky)
📷 [실습 화면 삽입]
ufw status verbose에서 Default 정책과 출발지 한정 규칙 확인 (Ubuntu)
firewall-cmd --zone=public --list-all 변경 후 형식 예시(값은 환경마다 다름)
public (active)
target: default
interfaces: ens33
sources:
services: dhcpv6-client
ports:
rich rules:
ufw status verbose 형식 예시(값은 환경마다 다름)
Status: active
Default: deny (incoming), allow (outgoing), deny (routed)
To Action From
-- ------ ----
22/tcp ALLOW IN 192.168.10.0/24
포트 정책 문서의 한 줄은 다음처럼 작성합니다. 형식 예시
| 서버 | 포트 | 방향 | 허용 출발지/목적지 | 사유 | 담당 | 검토일 |
|---|---|---|---|---|---|---|
| web01 | 443/tcp | IN | any | 대외 웹 서비스 | 웹 운영 | 분기 1회 |
| web01 | 22/tcp | IN | 192.168.10.5 (배스천) | 서버 관리 | 인프라 | 분기 1회 |
| db01 | 3306/tcp | IN | 192.168.20.30 (app01) | 애플리케이션 DB 접속 | DBA | 분기 1회 |
| db01 | any | OUT | 차단 (업데이트 저장소 예외) | 데이터 유출 방지 | 인프라 | 분기 1회 |
점검 체크리스트
| 관찰 내용 | 정상일 수 있는 경우 | 의심해야 하는 경우 |
|---|---|---|
| 외부 → 노출 금지 포트, 차단 로그 | 인터넷 전반의 자동 스캔(대부분 일상적) | 특정 출발지가 조직의 여러 IP·포트를 체계적으로 시도 |
| 외부 → 노출 금지 포트, 허용 로그 | (원칙적으로 없어야 함) 승인된 예외 규칙 | 규칙 문서에 없는 허용 → 즉시 정책 위반 조사 |
| 내부 PC → 외부 25 | 없음(메일 서버만 해당) | 스팸 발송 악성코드 감염 |
| 서버 → 외부 53 직접 | 내부 DNS 서버의 외부 조회 | 일반 서버가 외부 DNS로 직접 질의(설정 오류 또는 터널링, 08편) |
| 외부 → 445 / 내부 → 외부 445 | 없음 | 인바운드는 공격 시도, 아웃바운드는 자격 증명 유출 위험 |
# Rocky: 거부 패킷 로깅 활성화 후 확인 (실습 후 off 권장)
sudo firewall-cmd --set-log-denied=all
sudo journalctl -k --since "10 min ago" | grep -i "REJECT\|DROP"
# Ubuntu: ufw 로그 (로깅 활성화 필요)
sudo ufw logging on
sudo grep "UFW BLOCK" /var/log/ufw.log | tail
ufw 차단 로그 형식 예시(값은 환경마다 다름)
[UFW BLOCK] IN=ens33 OUT= SRC=203.0.113.77 DST=192.168.10.20 PROTO=TCP SPT=51544 DPT=3389 WINDOW=1024 SYN
다음 글: 23. 포트·프로토콜 보안 점검 체크리스트