EQVPS

Cách kiểm tra cổng đang mở trên VPS: cái gì đang lắng nghe, internet thấy gì và bất ngờ từ Docker

Xem mọi cổng máy chủ đang lắng nghe, tìm tiến trình đứng sau, quét máy chủ từ bên ngoài như kẻ tấn công vẫn làm và đóng những gì không cần. Kèm theo cổng Docker vẫn mở dù tường lửa đã bật. Mọi con số đều đo trên máy chủ Ubuntu 24.04 mới.

Một cổng mở rồi bị quên là lối vào kinh điển của máy chủ: cơ sở dữ liệu trên địa chỉ công khai, bảng điều khiển gỡ lỗi, container publish một cổng mà chẳng ai muốn. Việc kiểm tra chỉ mất một phút nếu bạn biết hai lệnh và một cái bẫy. Chúng tôi làm mọi thứ dưới đây trên một máy chủ Ubuntu 24.04 mới từ image của mình và quét nó từ một máy thứ hai, nên kết quả chính là những gì bạn sẽ thấy trên máy chủ của mình.

1. Cái gì đang lắng nghe

Lệnh là ss. Các chữ cái nghĩa là TCP, UDP, socket đang lắng nghe, số cổng và tên tiến trình:

sudo ss -tulpn

Trên máy chủ mới, lệnh in ra sáu dòng:

Netid State  Local Address:Port  Process
udp   UNCONN    127.0.0.54:53    systemd-resolve
udp   UNCONN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN    127.0.0.54:53    systemd-resolve
tcp   LISTEN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN       0.0.0.0:22    sshd
tcp   LISTEN          [::]:22    sshd

Cột quan trọng là Local Address. Nó cho biết ai có thể kết nối:

Địa chỉAi truy cập được
127.0.0.1:… hoặc 127.0.0.53Chỉ chương trình trên máy chủ này
0.0.0.0:…Bất kỳ ai qua IPv4, trừ khi tường lửa chặn
[::]:…Bất kỳ ai qua IPv6 (thường cả IPv4)
10.0.0.5:… (một địa chỉ cụ thể)Bất kỳ ai tới được địa chỉ đó

Vậy máy chủ mới chỉ mở ra ngoài đúng một thứ: SSH ở cổng 22, qua IPv4 và IPv6. Trình phân giải DNS trên 127.0.0.53 là riêng tư.

Để chỉ liệt kê những gì internet có thể thấy, hãy lọc bỏ các địa chỉ loopback:

sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'

Chạy lệnh này sau mỗi lần cài đặt. Chúng tôi đã cài nginx, Docker và một ứng dụng Python nhỏ, danh sách tăng từ 2 lên 10 dòng, trong đó có docker-proxy trên 0.0.0.0:8081 và một socket containerd trên một cổng localhost ngẫu nhiên.

2. Tiến trình nào chiếm cổng

Khi một cổng đã bị chiếm và bạn muốn biết ai chiếm:

sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'

lsof dễ đọc nhất. Với nginx, nó hiển thị một tiến trình master chạy bằng root và một worker chạy bằng www-data, cả hai trên *:80, cho IPv4 và IPv6. fuser chỉ in PID, tiện dùng trong script. Nếu cần giải phóng cổng, hãy dừng dịch vụ thay vì giết PID, nếu không systemd sẽ khởi động lại nó: sudo systemctl stop nginx.

3. Internet thấy gì

ss cho thấy góc nhìn của máy chủ. Góc nhìn của internet có thể khác, vì có tường lửa ở giữa hoặc vì dịch vụ gắn với 127.0.0.1. Để thấy bức tranh thật, hãy quét máy chủ từ một máy khác, laptop của bạn hoặc máy chủ thứ hai. Công cụ là nmap (apt install nmap, hoặc trình cài từ nmap.org trên Windows và macOS).

nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip

Dạng đầu kiểm tra 1.000 cổng phổ biến nhất, dạng thứ hai kiểm tra toàn bộ 65.535 cổng, dạng thứ ba kiểm tra một danh sách. Trên máy chủ mới của chúng tôi, trước khi có tường lửa:

Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
Nmap done: 1 IP address (1 host up) scanned in 6.83 seconds

Lần quét đầy đủ 65.535 cổng mất 8,9 giây và tìm thấy cùng một cổng duy nhất. Cổng đóng trả lời ngay bằng một gói reset, vì vậy quét chúng rất nhanh.

Có ba trạng thái quan trọng:

  • open: một chương trình đã chấp nhận kết nối. Đây là bề mặt tấn công của bạn.
  • closed: máy chủ trả lời rằng không có gì lắng nghe ở đó. An toàn, nhưng xác nhận máy chủ tồn tại và nó không chạy gì.
  • filtered: không có trả lời. Tường lửa đã loại bỏ gói tin. Trình quét không biết phía sau có dịch vụ hay không.

Với một cổng mà không cần cài gì, nc -zv ip-máy-chủ 443 báo succeeded hoặc refused, và sẽ treo đến hết thời gian chờ nếu cổng bị lọc. Với UDP, thêm -sU vào nmap và chuẩn bị chờ lâu; trên máy chủ của chúng tôi ba cổng UDP phổ biến là 53, 123 và 161 đều closed.

Lưu ý cho gói NAT: từ internet chỉ tới được cổng SSH mà chúng tôi chuyển tiếp cho bạn. Quét địa chỉ dùng chung sẽ thấy biên mạng của chúng tôi chứ không phải máy chủ của bạn, và các cổng khác không thể truy cập dù có gì lắng nghe trên đó. Với gói có địa chỉ IPv4 riêng, mọi cổng mở đều do bạn quản lý.

4. Đóng những gì không cần

Ba cách, từ tốt nhất đến rộng nhất.

Gắn vào localhost. Nếu chỉ chương trình trên máy chủ dùng một dịch vụ, hãy cho nó lắng nghe trên 127.0.0.1. Chúng tôi chạy một ứng dụng web nhỏ với --bind 127.0.0.1 8080: ss hiện nó trên 127.0.0.1:8080, còn nmap từ bên ngoài báo 8080/tcp closed. Với cơ sở dữ liệu, đây là mặc định đúng: Redis, MySQL và PostgreSQL trên Ubuntu mặc định lắng nghe localhost, và các hướng dẫn Redis và MySQL của chúng tôi giữ nguyên như vậy.

Dừng dịch vụ. sudo systemctl disable --now tên gỡ trình lắng nghe vĩnh viễn. Kiểm tra bằng ss rằng nó đã biến mất.

Bật tường lửa. Cho phép SSH trước, rồi những gì bạn phục vụ, rồi bật:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose

Kết quả quét từ bên ngoài thay đổi hoàn toàn:

Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8081/tcp open  blackice-icecap
Nmap done: 1 IP address (1 host up) scanned in 10.18 seconds

Mọi cổng không được phép chuyển từ closed sang filtered, và lần quét đầy đủ 65.535 cổng giờ mất 110 giây thay vì 8,9. Trình quét tốn nhiều thời gian hơn cho mỗi cổng, và biết ít hơn về máy chủ của bạn. Hướng dẫn UFW của chúng tôi nói về giới hạn tốc độ, cho phép một IP duy nhất và IPv6.

Nhưng hãy nhìn dòng thứ ba.

5. Bất ngờ từ Docker

Cổng 8081 vẫn mở dù tường lửa đã bật và không có quy tắc nào cho phép nó. Cổng này thuộc về container chúng tôi chạy bằng docker run -p 8081:80 nginx:alpine. Docker tự thêm quy tắc vào tường lửa của kernel, và chúng được xét trước quy tắc của ufw. Quy tắc nó ghi trên máy chủ của chúng tôi:

-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80

Mọi gói tin tới cổng 8081 đều được chuyển vào container trước khi ufw kịp lên tiếng. Mọi container có -p hoặc mục ports: đều làm vậy, và ss trung thực hiển thị nó là docker-proxy trên 0.0.0.0:8081.

Cách sửa là chỉ publish lên localhost:

docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine

Trong Compose, ghi "127.0.0.1:8081:80" dưới ports:. Sau thay đổi, ss hiện 127.0.0.1:8081, quy tắc Docker có thêm -d 127.0.0.1/32, và lần quét từ bên ngoài báo 8081/tcp filtered. Đặt nginx làm reverse proxy phía trước cho phần công khai, có HTTPS, để các cổng mở duy nhất trên máy chủ là 22, 80 và 443.

Danh sách kiểm tra sau mỗi thay đổi

  1. sudo ss -tulpn: mỗi dòng 0.0.0.0 hoặc [::] có phải thứ bạn muốn mở không?
  2. nmap ip-máy-chủ từ laptop: các cổng mở có khớp không?
  3. Cơ sở dữ liệu, cache hoặc trang quản trị trên địa chỉ công khai: chuyển sang 127.0.0.1 hoặc ra sau tường lửa ngay hôm nay.
  4. Mỗi mục ports: của Docker: có bắt đầu bằng 127.0.0.1: nếu không phải cổng web công khai?
  5. SSH mở cho tất cả: thêm fail2ban hoặc chỉ đăng nhập bằng khóa.

Trên Windows Server, phép kiểm tra tương tự là Get-NetTCPConnection -State Listen, và các quy tắc nằm trong Windows Firewall. Mọi gói Linux, từ Nano $3 trở lên, đều có phiên bản với địa chỉ IPv4 riêng, và ở đó những gì bạn thấy trong ss là những gì cả thế giới thấy, trừ những gì tường lửa của bạn chặn.

FAQ

VPS mới có những cổng nào đang mở?

Trên image Ubuntu 24.04 của chúng tôi chỉ có một: SSH ở cổng 22. Ngoài ra chỉ có trình phân giải DNS cục bộ trên 127.0.0.53 và 127.0.0.54 lắng nghe, và internet không chạm tới được. Quét toàn bộ 65.535 cổng TCP từ một máy khác tìm thấy đúng một cổng mở.

Cổng closed khác cổng filtered thế nào?

Closed nghĩa là máy chủ trả lời rằng không có gì lắng nghe ở đó, nên trình quét biết ngay. Filtered nghĩa là không có trả lời nào, đó là điều tường lửa làm khi loại bỏ gói tin. Cả hai đều chặn kẻ xâm nhập, nhưng filtered còn che giấu dịch vụ nào đang tồn tại và làm một lần quét đầy đủ chậm hơn khoảng mười hai lần trên máy chủ của chúng tôi.

Vì sao ss hiện một cổng mà nmap báo closed?

Dịch vụ chỉ lắng nghe trên 127.0.0.1, địa chỉ loopback. Chương trình trên chính máy chủ kết nối được, từ bên ngoài thì không ai. Trong ss hãy xem cột Local Address: 127.0.0.1:8080 là riêng tư, còn 0.0.0.0:8080 hoặc [::]:8080 có thể truy cập từ internet nếu tường lửa cho phép.

Tôi đã bật ufw, sao cổng Docker vẫn mở?

Docker tự ghi quy tắc tường lửa và chúng được xét trước quy tắc của ufw. Một container chạy với -p 8081:80 vẫn truy cập được từ bên ngoài trên máy chủ của chúng tôi khi ufw đang bật và không có quy tắc nào cho 8081. Hãy publish lên localhost, -p 127.0.0.1:8081:80, và đặt nginx hoặc Caddy phía trước cho phần công khai.

Làm sao kiểm tra một cổng từ máy tính của tôi?

Chạy nc -zv ip-máy-chủ 443 cho một cổng, hoặc cài nmap và chạy nmap ip-máy-chủ cho một nghìn cổng phổ biến nhất. Với gói NAT, từ internet chỉ cổng SSH đã được chuyển tiếp cho bạn trả lời; mọi thứ khác không thể truy cập theo thiết kế.

Bình luận

Chưa có bình luận nào. Hãy là người đầu tiên.

Để lại bình luận

Bình luận được kiểm duyệt trước khi hiển thị.