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.53 | Chỉ 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
sudo ss -tulpn: mỗi dòng0.0.0.0hoặc[::]có phải thứ bạn muốn mở không?nmap ip-máy-chủtừ laptop: các cổng mở có khớp không?- 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.1hoặc ra sau tường lửa ngay hôm nay. - Mỗi mục
ports:của Docker: có bắt đầu bằng127.0.0.1:nếu không phải cổng web công khai? - 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.
Bình luận
Chưa có bình luận nào. Hãy là người đầu tiên.