본문 바로가기
서버연구 블로그 서버연구 블로그

서버에서 불필요한 Port를 열어두면 발생할 수 있는 문제

읽는 시간 약 14분

Linux 서버를 운영하다 보면 웹 서비스에는 80, 443 포트만 필요한데도 SSH, 데이터베이스, 모니터링 도구, 테스트용 애플리케이션 포트까지 외부에서 접근 가능한 상태로 남아 있는 경우가 있다.

서버가 정상적으로 동작하고 있다면 당장은 문제가 없어 보인다. 하지만 사용하지 않는 Port를 외부에 노출해 두는 것은 공격자가 서버에 접근할 수 있는 경로를 하나씩 늘려 놓는 것과 같다.

그렇다고 단순히 “열린 Port가 많으면 위험하다”라고만 이해하면 정확하지 않다. 실제 Linux 서버에서는 프로세스가 Port를 Listen하는 상태와 외부 네트워크에서 해당 Port에 접근할 수 있는 상태를 구분해야 한다.

이번 글에서는 Port가 서버 내부에서 어떻게 열리는지부터 불필요한 Port가 보안에 어떤 영향을 주는지, 실제 운영 환경에서는 무엇을 확인하고 어떻게 정리해야 하는지 살펴본다.

1. 서버의 Port는 왜 열려 있을까?

TCP나 UDP를 사용하는 서버 프로그램은 클라이언트의 요청을 받기 위해 특정 Port에 Socket을 생성한다.

예를 들어 Nginx가 80번 Port에서 요청을 기다리고 있다면 구조는 대략 다음과 같다.

Client
   │
   │ TCP 80
   ▼
Linux Kernel
   │
   ▼
Listening Socket :80
   │
   ▼
Nginx

Linux에서 서버 프로그램은 Socket을 생성하고 IP 주소와 Port를 바인딩한 뒤, TCP 서비스라면 listen()을 통해 들어오는 Connection을 받을 준비를 한다.

listen() 상태의 Socket은 새로운 연결 요청을 받아들일 수 있는 수동 Socket으로 동작한다.

따라서 Port 자체가 독립적으로 열려 있는 것이 아니다.

Port 뒤에는 해당 Port에서 요청을 기다리는 프로세스가 존재한다.

예를 들어 다음과 같은 구성이 있을 수 있다.

22    → sshd
80    → nginx
443   → nginx
3306  → mysqld
6379  → redis-server
8080  → Java Application

문제는 실제로 필요하지 않은 서비스까지 계속 실행되고 있을 때 시작된다.

2. Listen 중인 Port와 외부에 열린 Port는 다르다

서버 운영에서 가장 많이 혼동하는 부분이다.

다음 명령을 실행했다고 가정해 보자.

ss -lntp

ss의 -l 옵션은 Listening Socket을 표시하고, -t는 TCP, -n은 Port를 숫자로 표시하며, -p는 관련 프로세스 정보를 확인하는 데 사용한다.

결과가 다음과 같다고 해보자.

LISTEN 0 511  0.0.0.0:80      0.0.0.0:*  users:(("nginx",pid=1200))
LISTEN 0 128  0.0.0.0:22      0.0.0.0:*  users:(("sshd",pid=850))
LISTEN 0 128  127.0.0.1:6379  0.0.0.0:*  users:(("redis-server",pid=1500))

여기서 80과 22는 0.0.0.0에 바인딩되어 있다.

이는 모든 IPv4 인터페이스에서 해당 Port로 들어오는 Connection을 받을 수 있도록 Socket이 구성됐다는 의미다.

하지만 Redis의 6379번 Port는 127.0.0.1에만 바인딩되어 있다.

127.0.0.1:6379

이 경우 기본적으로 서버 내부의 Loopback 인터페이스를 통해서만 접근할 수 있다.

따라서 단순히 “6379 Port가 LISTEN 중이다“라는 사실만 보고 인터넷에 Redis가 노출됐다고 판단하면 안 된다.

반대로 0.0.0.0:6379 또는 IPv6의 [::]:6379처럼 모든 인터페이스에서 Listen하고 있다면 방화벽과 네트워크 접근 정책을 추가로 확인해야 한다.

3. 외부 Port 노출은 세 단계로 확인해야 한다

실제 운영 환경에서 중요한 분석 포인트가 있다.

특정 Port가 인터넷에서 접근 가능한지는 ss 결과 하나만으로 결정되지 않는다.

구조적으로는 다음 세 가지를 같이 봐야 한다.

Application
   │
   │ Bind / Listen
   ▼
Linux Server
   │
   │ Host Firewall
   ▼
Network Firewall
Security Group
ACL
   │
   ▼
Internet

첫 번째는 애플리케이션이 어느 IP와 Port에서 Listen하고 있는지다.

두 번째는 Linux 서버 자체의 nftables, firewalld, UFW 같은 Host Firewall 정책이다.

세 번째는 클라우드 Security Group이나 네트워크 Firewall처럼 서버 앞단에 존재하는 접근 제어 정책이다.

예를 들어 애플리케이션이 0.0.0.0:3306에서 MySQL을 Listen하고 있더라도 Security Group에서 3306번 접근을 차단한다면 인터넷에서 직접 접근할 수 없다.

반대로 Security Group에서 3306번을 전체 인터넷에 허용하고 MySQL도 모든 인터페이스에서 Listen한다면 데이터베이스가 직접 노출될 수 있다.

따라서 Listening Port와 Internet Exposed Port는 같은 의미가 아니다.

이 차이를 구분하는 것이 실제 서버 점검에서 매우 중요하다.

4. 불필요한 Port가 위험한 이유는 무엇일까?

Port 자체가 서버를 공격하는 것은 아니다.

실제 위험은 Port 뒤에서 동작하는 서비스가 외부에 노출되는 것에서 발생한다.

예를 들어 예전에 테스트 목적으로 설치했던 관리 프로그램이 특정 Port에서 계속 Listen하고 있다고 가정해 보자.

운영자는 이미 그 프로그램을 사용하지 않기 때문에 업데이트도 하지 않을 가능성이 높다.

Internet
   │
   ▼
불필요하게 열린 Port
   │
   ▼
오래된 Service
   │
   ▼
알려진 Vulnerability

이 경우 공격자는 인터넷에서 서버를 스캔하면서 어떤 Port가 열려 있는지 확인하고, 해당 Port에서 동작하는 서비스의 종류와 버전을 조사할 수 있다.

서비스에 취약점이 존재한다면 공격 경로로 이용될 가능성이 생긴다.

그래서 보안에서는 외부에 노출되는 서비스를 필요한 것만 남기는 것을 Attack Surface를 줄이는 과정으로 본다.

CISA 역시 불필요하거나 사용하지 않는 Port, Protocol, Service를 비활성화하고 인터넷에 반드시 노출해야 하는 서비스는 접근 제어와 패치 상태를 관리하도록 권고하고 있다.

5. 실제 서버에서 불필요한 Port는 어떻게 찾을까?

가장 먼저 현재 TCP와 UDP Listening Socket을 확인한다.

ss -lntup

여기서 중요한 것은 Port 번호만 보는 것이 아니다.

다음과 같이 판단해야 한다.

어떤 Port인가?
      ↓
어떤 Process가 사용하고 있는가?
      ↓
어느 IP에 Bind되어 있는가?
      ↓
현재 서비스에 필요한가?
      ↓
외부에서 접근할 필요가 있는가?

예를 들어 다음처럼 Java가 8080번 Port에서 Listen하고 있다고 해보자.

LISTEN 0 100 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=2145))

운영 중인 웹 애플리케이션이라면 필요한 Port일 수 있다.

하지만 Nginx Reverse Proxy를 통해서만 Java 애플리케이션에 접근하도록 구성했다면 Java가 반드시 외부 인터페이스에 직접 노출될 필요가 있는지도 확인해야 한다.

구조가 다음과 같다면,

Internet
   │
   ▼
Nginx :443
   │
   ▼
Application :8080

애플리케이션의 8080번 Port를 인터넷에서 직접 접근할 수 있게 열어 둘 이유가 없는 경우가 많다.

이것이 단순 Port 목록 확인과 실제 서버 구조 분석의 차이다.

6. 방화벽 정책도 함께 확인해야 한다

Listening Port를 확인했다면 실제 접근 정책을 확인한다.

firewalld를 사용하는 환경에서는 다음과 같이 볼 수 있다.

firewall-cmd --list-all

UFW 환경이라면 다음 명령을 사용할 수 있다.

ufw status verbose

nftables를 직접 사용하는 서버라면 현재 Rule Set을 확인한다.

nft list ruleset

클라우드 서버라면 여기서 끝나지 않는다.

AWS Security Group과 같은 외부 Firewall 정책도 같이 확인해야 한다.

예를 들어 다음과 같은 정책은 특히 주의해서 봐야 한다.

TCP 3306
Source 0.0.0.0/0

0.0.0.0/0은 특정 관리 IP가 아니라 모든 IPv4 주소를 대상으로 한다.

따라서 데이터베이스처럼 외부 전체에 공개할 필요가 없는 서비스라면 실제 서비스 구조에 맞춰 접근 Source를 제한할 필요가 있다.

7. 불필요한 Port는 어떻게 정리해야 할까?

Port를 발견했다고 바로 방화벽에서 차단하는 것부터 시작해서는 안 된다.

먼저 왜 해당 Port가 열려 있는지 확인하는 것이 우선이다.

사용하지 않는 서비스라면 해당 프로세스 또는 서비스를 중지하고 부팅 시 자동 실행되는지도 확인해야 한다.

예를 들어 systemd로 관리되는 서비스라면 다음과 같이 상태를 확인할 수 있다.

systemctl status <service>

서비스가 정말 불필요하다는 것이 확인됐다면 중지와 자동 실행 정책을 검토한다.

반대로 서비스 자체는 필요하지만 외부 접근만 필요하지 않다면 서비스를 제거하는 것이 아니라 Bind Address나 Firewall 정책을 조정하는 것이 맞다.

예를 들어 데이터베이스 서버가 Application Server에서만 접근되어야 한다면 구조는 다음과 같이 만드는 편이 안전하다.

Internet
   X
   │
Database Port
   │
Application Server
   │
   ▼
Database Server

즉 해결 방법은 항상 “Port를 닫는다” 하나가 아니다.

서비스 중지, Bind 범위 제한, Host Firewall 적용, Security Group 또는 ACL 제한 중 현재 서버 구조에 맞는 방법을 선택해야 한다.

설정을 변경한 뒤에는 반드시 서비스를 다시 점검해야 한다.

ss -lntup

그리고 외부 접근 정책까지 다시 확인해 의도했던 Port만 노출되어 있는지 검증한다.

8. 운영 서버에서는 Port 목록을 기준화하는 것이 중요하다

한 번 불필요한 Port를 제거했다고 관리가 끝나는 것은 아니다.

애플리케이션 설치나 모니터링 Agent 추가, 테스트 프로그램 실행, 장애 대응 과정에서 새로운 Listening Port가 생길 수 있기 때문이다.

그래서 운영 서버에서는 정상 상태에서 어떤 Port가 열려 있어야 하는지를 알고 있어야 한다.

예를 들어 웹서버라면 현재 서버 구조에 따라 정상적인 외부 노출 Port가 80, 443, 제한된 관리망의 SSH 정도일 수 있다.

평소 상태를 알고 있으면 이후 ss -lntup 결과에 처음 보는 8080, 9000, 10000 같은 Port가 나타났을 때 바로 확인할 수 있다.

여기서 중요한 것은 Port 번호만 보고 정상과 비정상을 판단하지 않는 것이다.

같은 8080번이라도 정상 애플리케이션이 사용할 수도 있고, 과거 테스트 프로그램이 남긴 Port일 수도 있다.

결국 판단 기준은 Port 번호가 아니라 어떤 Process가 왜 Listen하고 있고, 누구에게 접근이 허용되어 있는가이다.

9. 정리

서버에서 불필요한 Port를 열어두는 문제의 본질은 Port 숫자가 많다는 데 있지 않다.

Port 뒤에서 실행되는 불필요한 서비스가 외부에 노출되면서 서버의 공격 가능 영역이 넓어진다는 것이 핵심이다.

실제 서버에서는 다음 흐름으로 점검하는 것이 좋다.

Listening Port 확인
        ↓
Process 확인
        ↓
Bind Address 확인
        ↓
서비스 필요성 판단
        ↓
Host Firewall 확인
        ↓
Security Group / ACL 확인
        ↓
불필요한 노출 제거

특히 ss에서 LISTEN 상태로 보인다는 이유만으로 외부에 Port가 공개됐다고 단정해서는 안 된다.

애플리케이션의 Bind 상태, Linux Firewall, 서버 앞단의 Network Firewall 또는 Security Group까지 함께 확인해야 실제 외부 노출 여부를 판단할 수 있다.

운영 서버의 보안은 특별한 보안 프로그램 하나를 설치하는 것에서 시작되지 않는다. 지금 서버가 어떤 서비스를 실행하고 있고, 그 서비스가 어느 네트워크까지 노출되어 있는지를 정확히 아는 것부터 시작한다.

사용하지 않는 서비스와 불필요한 외부 접근 경로를 줄이는 것은 가장 기본적인 서버 보안이면서, 실제 공격자가 이용할 수 있는 Attack Surface를 줄이는 효과적인 방법이다.

instone
함께 보면 좋은 글

댓글 0

첫 댓글을 남겨보세요.

error: Content is protected !!

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.