제공 서비스
웹 보안 점검 · 무료 단건 외부 공격표면 관리 · 지속 자동 AI 취약점 진단 · 신규 모의해킹 · 침투 테스트
요금제 스토어 블로그 파트너 마이페이지 무료 보안 점검
가이드 2026.03.17 · 조회 923

웹 서비스 운영자를 위한 포트 보안 가이드

서버 포트 하나 잘못 열어두면 DB가 통째로 털린다. 운영자 관점에서 꼭 알아야 할 포트 보안 정리.

S
보안 전문 기업 SENTRIX 레드팀
해킹대회 수상 · 보안 실무 10년 · 실전 진단 경험을 바탕으로 작성합니다.
이 글의 취약점, 내 사이트엔 없을까요? URL 하나로 30초 무료 점검.

포트가 열려있다 = 문이 잠기지 않은 집

실제 모의해킹을 해보면 포트 스캔 결과로 공격 진입점을 찾는 데 5분도 안 걸린다. 특히 개발 편의를 위해 열어둔 DB 포트, 잊어버린 개발 서버 포트, 이런 게 사고의 시작이다.

공격자 입장에서 서버를 뚫는 첫 단계는 "이 IP에서 어떤 서비스가 돌고 있나"를 파악하는 정찰(reconnaissance)이다. 방화벽 설정이 허술하면 이 단계에서 이미 승부가 갈린다. 웹 서버는 80/443만 열려 있어야 정상인데, 개발하다 잠깐 열어둔 3306(MySQL)이나 6379(Redis)가 0.0.0.0/0으로 노출돼 있으면, 공격자는 웹 애플리케이션을 건드릴 필요도 없이 DB에 직접 붙는다. 애써 만든 로그인 화면, 권한 검증 로직을 전부 우회하고 데이터를 통째로 가져가는 것이다.

Shodan 같은 서비스는 인터넷에 노출된 서버 포트를 자동으로 인덱싱한다. 내 서버 IP를 Shodan에 검색해보면 외부에서 어떻게 보이는지 바로 확인할 수 있다. 공격자는 특정 서버를 노리기보다, "인증 없이 열린 Redis" "노출된 MongoDB" 같은 조건으로 전 세계 서버를 한 번에 검색한다. 즉, 내 서버가 작고 무명이라 안전한 게 아니라, 노출돼 있으면 자동화된 스캔에 반드시 걸린다. 배포 직후 몇 시간 안에 봇의 접속 시도가 시작되는 게 요즘 현실이다.

공격자는 이렇게 찾는다, 5분짜리 정찰

레드팀 관점에서 노출된 포트를 찾는 과정은 단순하다. 대상 IP에 nmap 한 줄이면 열린 포트와 서비스 버전까지 나온다.

# 공격자가 실제로 돌리는 스캔 (열린 포트 + 서비스 버전 식별)
nmap -sV -p- --min-rate 1000 대상서버IP

# 결과 예시
# 22/tcp    open  ssh     OpenSSH 8.2p1
# 3306/tcp  open  mysql   MySQL 5.7.38    ← 외부에 열린 DB, 여기서 게임 끝
# 6379/tcp  open  redis   Redis 6.2.6     ← 인증 없으면 즉시 장악

여기서 3306이나 6379가 뜨는 순간, 남은 건 무차별 대입이나 알려진 취약점 공격뿐이다. 방화벽에서 이 포트들이 애초에 응답하지 않았다면 정찰 자체가 실패한다. 보안의 첫 단추는 "공격자에게 보이지 않는 것"이다.

반드시 외부 접근을 차단해야 할 포트

아래 포트들은 웹 서비스 운영에서 외부(인터넷)에 열려 있을 이유가 거의 없다. 애플리케이션 서버와 같은 사설망(VPC) 안에서만 통신하면 되기 때문이다. 각 포트가 왜 위험한지, 뚫리면 무슨 일이 벌어지는지 구체적으로 짚는다.

  • 3306, MySQL/MariaDB: DB 포트가 외부에 열리면 직접 접속 공격이 가능하다. 기본 계정(root)에 대한 무차별 대입, 알려진 CVE를 통한 인증 우회 시도가 자동으로 들어온다. 뚫리면 전체 테이블 덤프, 데이터 위·변조, 랜섬(데이터 삭제 후 몸값 요구)까지 이어진다.
  • 5432, PostgreSQL: MySQL과 동일. 특히 trust 인증 방식이 남아 있으면 비밀번호조차 없이 접속된다. Supabase 등 매니지드 서비스를 쓰지 않고 직접 PostgreSQL을 올린 경우 반드시 확인해야 한다.
  • 27017, MongoDB: 과거 버전은 기본 설정에 인증이 없어, 열려 있으면 DB 전체가 무인증으로 공개된다. 실제로 "노출된 MongoDB의 데이터를 지우고 비트코인을 요구하는" 대규모 자동화 공격이 수년째 반복되고 있다. 열려 있으면 발견되는 건 시간문제다.
  • 6379, Redis: 기본 설정에 인증이 없고, 열려 있으면 단순 데이터 유출을 넘어 서버 권한 탈취로 직결된다. 공격자는 Redis의 파일 쓰기 기능을 악용해 SSH 공개키나 크론잡(cron)을 심어 서버를 완전히 장악할 수 있다. 위험도 최상위.
  • 8080, 8443, 개발/대체 웹 서버: 개발 환경에서만 쓰고 프로덕션에서 닫아야 한다. 인증 없는 관리 콘솔(Tomcat Manager, Jenkins, 각종 어드민 대시보드)이 이 포트에 붙어 있는 경우가 많아, 그대로 노출되면 코드 배포 권한까지 넘어간다.
  • 9200, Elasticsearch: 인증 없이 열리면 저장된 전체 데이터를 REST API 한 번으로 조회할 수 있다. 로그·검색 인덱스에 개인정보나 세션 토큰이 쌓여 있는 경우가 많아 유출 파급이 크다.

내 서버 포트, 지금 바로 확인하는 법

"열려 있는지 아닌지"를 감으로 판단하지 말고 직접 봐야 한다. 두 가지 관점이 필요하다, 서버 내부에서 무엇이 리스닝 중인가, 그리고 외부에서 무엇이 보이는가는 다르다. 방화벽이 중간에서 막아주기 때문이다.

# [서버 내부] 실제로 어떤 포트가 열려 리스닝 중인지
sudo ss -tlnp
# 또는
sudo netstat -tlnp

# 0.0.0.0:3306 이 보이면 → 모든 인터페이스에서 접속 허용 (위험 신호)
# 127.0.0.1:3306 이면 → 로컬만 허용 (정상)

# [외부 관점] 다른 서버나 로컬 PC에서, 내 서버가 어떻게 보이는지
nmap -p 22,3306,5432,6379,27017,9200 내서버IP
# 'open' 이 뜨는 포트가 인터넷에 노출된 포트다

가장 확실한 방어는 DB를 로컬호스트(127.0.0.1)에만 바인딩하는 것이다. MySQL은 /etc/mysql/mysql.conf.d/mysqld.cnfbind-address = 127.0.0.1, Redis는 redis.confbind 127.0.0.1requirepass 설정을 확인한다. 애플리케이션과 DB가 다른 서버에 있다면, 사설망 대역만 허용하고 인터넷 전체(0.0.0.0/0)는 절대 열지 않는다.

AWS Security Group 기본 설정

클라우드에서는 서버 안 방화벽(iptables/ufw)보다 Security Group(보안 그룹)이 1차 방어선이다. 인바운드 규칙에서 허용하지 않은 포트는 서버에 도달조차 못 한다. 문제는 개발 중 "일단 되게 하려고" 0.0.0.0/0으로 열어둔 규칙이 그대로 남아 있는 경우다.

# 현재 열린 포트 확인 (AWS CLI)
aws ec2 describe-security-groups \
  --filters "Name=group-id,Values=sg-xxxx" \
  --query 'SecurityGroups[*].IpPermissions'

# 위험한 규칙 빠르게 찾기: 0.0.0.0/0 으로 열린 것만 뽑기
aws ec2 describe-security-groups \
  --query 'SecurityGroups[*].IpPermissions[?contains(IpRanges[].CidrIp, `0.0.0.0/0`)]'

# 특정 포트 닫기 (예: 외부에 열린 MySQL 회수)
aws ec2 revoke-security-group-ingress \
  --group-id sg-xxxx \
  --protocol tcp \
  --port 3306 \
  --cidr 0.0.0.0/0

원칙은 최소 권한(least privilege)이다. 웹 서버 보안 그룹은 80/443만 인터넷에 열고, SSH(22)는 내 사무실/집 고정 IP 또는 VPN 대역만 허용한다. DB는 별도 보안 그룹으로 분리해, "웹 서버 보안 그룹에서 오는 트래픽만" 허용하도록 소스를 CIDR이 아닌 보안 그룹 ID로 지정하면 IP가 바뀌어도 안전하다.

# 안전한 패턴: DB 보안 그룹은 웹 서버 보안 그룹에서 온 3306만 허용
aws ec2 authorize-security-group-ingress \
  --group-id sg-db \
  --protocol tcp --port 3306 \
  --source-group sg-web   # ← CIDR이 아닌 보안 그룹 참조

자가점검: 우선순위대로 처리하기

지금 당장 확인해야 할 순서는 명확하다.

  1. DB·캐시 포트(3306/5432/6379/27017/9200)가 0.0.0.0/0인가, 하나라도 있으면 최우선 회수. 사고로 직결된다.
  2. SSH(22)가 전체 공개인가, 특정 IP/VPN으로 제한. 무차별 대입 시도가 가장 많이 들어오는 포트다.
  3. 8080·8443 같은 개발/관리 포트가 열려 있는가, 프로덕션에서 닫는다.
  4. 불명확한 규칙, "누가 왜 열었는지 모르는" 규칙은 닫고 문제가 생기는지 관찰한다.

SSH 포트 보안 강화

SSH는 서버 관리의 핵심 통로라 완전히 닫을 수는 없다. 대신 비밀번호 인증을 없애고 키 기반으로 전환하는 것만으로도 무차별 대입 공격을 원천 차단한다. 인터넷에 열린 22번 포트에는 하루에도 수천 건씩 자동화된 로그인 시도가 들어온다, root/admin/ubuntu 같은 흔한 계정에 흔한 비밀번호를 대입하는 봇이다. 키 인증만 허용하면 이 시도들은 전부 무의미해진다.

# /etc/ssh/sshd_config 권장 설정
Port 22                      # 변경 권장 (22 대신 다른 포트 — 자동 스캔 소음 감소)
PermitRootLogin no           # root 직접 로그인 차단
PasswordAuthentication no    # 키 기반 인증만 허용 (무차별 대입 원천 차단)
PubkeyAuthentication yes
MaxAuthTries 3               # 시도 횟수 제한
AllowUsers ubuntu            # 특정 유저만 허용
LoginGraceTime 30            # 인증 대기 시간 단축

sudo systemctl restart sshd

포트를 22에서 다른 번호로 바꾸는 건 보안 그 자체는 아니지만(포트를 숨긴다고 안전해지는 게 아니다), 자동 스캔 봇의 표적에서 벗어나 로그 노이즈를 크게 줄여준다. 진짜 방어는 PasswordAuthentication no보안 그룹의 IP 제한 두 가지다.

여기에 fail2ban을 더하면, 짧은 시간에 반복 실패하는 IP를 자동으로 차단해 방어층이 하나 더 생긴다.

# fail2ban 설치 및 SSH 보호 활성화 (Ubuntu 기준)
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban

# 현재 차단된 IP 확인
sudo fail2ban-client status sshd

자가점검: SSH 설정이 안전한가

설정을 바꿨다면 실제로 적용됐는지 확인한다. 비밀번호로 접속이 여전히 되는지 직접 시도해보는 게 가장 확실하다.

# 비밀번호 인증이 정말 꺼졌는지 외부에서 테스트
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no ubuntu@내서버IP
# "Permission denied (publickey)" 가 떠야 정상 (비밀번호 프롬프트가 뜨면 아직 위험)

# 현재 sshd에 적용된 실제 설정 값 확인
sudo sshd -T | grep -E "passwordauthentication|permitrootlogin|maxauthtries"

Nginx로 불필요한 경로 차단

포트를 잠갔어도, 80/443으로 들어오는 웹 요청 중에는 여전히 위험한 것들이 있다. 대표적으로 .env(환경변수·API 키·DB 비밀번호), .git(전체 소스코드 이력), 그리고 존재하지도 않는 워드프레스 관리자 경로를 노리는 자동 공격이다. 이런 요청은 애플리케이션까지 갈 필요 없이 웹 서버 단에서 잘라내는 게 깔끔하다.

# .env, .git 등 민감 파일 접근 차단
location ~ /\.env {
    deny all;
    return 404;
}

location ~ /\.git {
    deny all;
    return 404;
}

# 알려진 취약 경로 차단 (워드프레스·DB 관리도구를 노리는 자동 스캔)
location ~* /(wp-admin|wp-login|phpmyadmin|adminer) {
    deny all;
    return 404;
}

# 숨김 파일 전체를 한 번에 차단하는 더 넓은 규칙
location ~ /\.(?!well-known) {
    deny all;
    return 404;
}

.env 노출은 포트 개방만큼이나 치명적이다. 이 파일 하나에 DB 접속 정보, 결제 PG사 시크릿 키, 외부 API 토큰이 전부 들어 있기 때문이다. 봇은 신규 배포된 도메인에 /.env, /.git/config를 자동으로 요청해본다. 실제로 응답이 200으로 파일을 내려주면, 그 안의 키로 클라우드 계정까지 장악당하는 일이 벌어진다.

자가점검: 민감 파일이 새고 있는가

브라우저 주소창이나 curl로 직접 요청해보면 5초 만에 확인된다.

# 민감 파일이 외부에서 다운로드되는지 직접 확인
curl -I https://내도메인.com/.env
curl -I https://내도메인.com/.git/config

# 200 OK 가 뜨면 → 즉시 차단 + 노출된 모든 키/비밀번호 재발급
# 404 Not Found 가 뜨면 → 정상

만약 .env.git이 노출된 흔적이 있었다면, 차단하는 것만으로는 부족하다. 이미 유출됐다고 가정하고 관련 키·비밀번호를 전부 재발급해야 한다. 노출된 키는 봇이 이미 수집해 갔을 수 있기 때문이다.

포트·인프라 보안, 한 번에 점검하기

지금까지의 항목을 정리하면 이렇다, DB·캐시 포트 회수 → SSH 키 인증 전환 → 민감 파일 경로 차단. 이 세 가지만 처리해도 외부 공격 표면의 대부분이 사라진다.

문제는 서버가 늘어나고 배포가 잦아질수록, 어제 안전했던 설정이 오늘 무너진다는 것이다. 새 인스턴스를 띄우며 보안 그룹을 복사하다 실수하고, 급하게 열어둔 포트를 닫는 걸 잊는다. 그래서 수동 점검 한 번으로 끝나지 않고 주기적으로 확인해야 한다.

포트 점검은 CodeScan에서 자동으로 해준다. URL 하나만 넣으면 자주 열려 있는 위험 포트, 노출된 민감 파일, 보안 헤더 누락, SSL 설정까지 21개 항목을 스캔해서 등급과 함께 리포트로 정리해준다. 모의해킹 실무 관점에서 "공격자가 가장 먼저 보는 것"들을 우선으로 잡아낸다.

→ 내 서버 포트·보안 상태 무료로 점검하기

포트 서버보안 가이드 인프라

내 사이트도 점검해보세요

URL 하나면 21개 항목을 30초에 무료 점검합니다. 회원가입·카드 없이.

추천 상품
웹서비스 런칭 전 보안 세팅
런칭 전에 반드시 해야 하는 보안 설정을 원격으로 직접 해드립니다. HTTPS, 환경변수 분리, 보안 헤더…
220,000원 150,000원

AI 코딩 보안 체크리스트 받기

AI 코딩 보안 체크리스트(PDF)를 무료로 받아보세요.