SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

Cổng Linux là gì và service lắng nghe thế nào

Hiểu cổng 1–65535, TCP và UDP, rồi dùng ss để xem service nào đang listening. Phân biệt cổng local với cổng public trước khi mở firewall.

Port thực sự là gì

Port là một số cho phép một server chạy nhiều service cùng lúc mà traffic của chúng không bị trộn lẫn. VPS của bạn có một địa chỉ IP, nhưng có thể đồng thời chạy web server, SSH server và database. Khi một packet đến, hệ điều hành cần biết packet đó dành cho service nào. Số port cung cấp thông tin này. Traffic HTTPS thường đi đến port 443, còn SSH đi đến port 22. Địa chỉ IP đưa packet đến server; port đưa packet đến đúng chương trình trên server đó.

Port là một số 16-bit: 16 bit cho các giá trị từ 0 đến 65535, nhưng 0 được dành riêng, nên trên thực tế port chạy từ 1 đến 65535. Các port dưới 1024 là port "well-known". Theo mặc định, Linux chỉ cho root hoặc chương trình được cấp capability CAP_NET_BIND_SERVICE mở các port này. Vì vậy, các service tiêu chuẩn thường dùng chúng: 22 cho SSH, 80 cho HTTP, 443 cho HTTPS và 53 cho DNS. sysctl net.ipv4.ip_unprivileged_port_start có thể thay đổi ngưỡng này, nhưng mặc định là 1024. Các port từ 1024 trở lên có thể được chương trình thông thường sử dụng.

Có hai loại port: TCP và UDP. Cùng một số port nhưng ở TCP và UDP là hai port riêng biệt. TCP là protocol hướng kết nối mà phần lớn service sử dụng, chẳng hạn SSH, HTTP và database. UDP không hướng kết nối và được dùng cho những thứ như DNS và một số VPN. Khi mở firewall, bạn thường phải chỉ rõ protocol nào, ví dụ 22/tcp.

Listening nghĩa là một chương trình đang chờ trên một cổng

Một chương trình muốn nhận kết nối sẽ yêu cầu kernel “listen” trên một cổng. Từ thời điểm đó, cổng này được mở trên máy và chương trình sẽ xử lý mọi kết nối gửi đến đó, tùy theo firewall. Cổng không có chương trình nào đang listen sẽ từ chối kết nối. Vì vậy, câu hỏi đầu tiên trong mọi lần kiểm tra bảo mật là: chương trình nào đang listen và listen ở đâu.

Lệnh dùng để kiểm tra là ss:

sudo ss -tlnp

Các flag cho biết TCP (t), chỉ hiển thị socket đang listen (l), hiển thị cổng ở dạng số (n, để bạn thấy 22 thay vì ssh), và hiển thị process đang sở hữu socket (p). Kết quả thường có dạng:

State   Recv-Q  Local Address:Port   Process
LISTEN  0       0.0.0.0:22           sshd
LISTEN  0       127.0.0.1:5432       postgres
LISTEN  0       [::]:80              nginx

Cột Process cho biết chương trình nào sở hữu từng cổng. Đây là cách xác định một chương trình mà bạn không định để chạy nhưng vẫn đang chạy.

Cột Local Address mới là phần cần chú ý

Hãy đọc kỹ địa chỉ đứng trước mỗi port, vì địa chỉ đó quyết định ai có thể truy cập service. Bạn sẽ thường xuyên gặp 3 trường hợp sau.

0.0.0.0:22 nghĩa là "listen trên mọi địa chỉ IPv4 mà máy này có", bao gồm cả địa chỉ public. Nếu firewall cho phép, service có thể được truy cập từ Internet qua IPv4.

[::]:80 có ý nghĩa tương tự với IPv6: listen trên mọi địa chỉ IPv6, bao gồm cả địa chỉ public. Nhiều chương trình bind vào đây theo mặc định. Trên Linux, một socket :: thường cũng chấp nhận IPv4.

127.0.0.1:5432 nghĩa là "chỉ listen trên loopback". 127.0.0.1 là địa chỉ máy dùng để giao tiếp với chính nó. Theo thiết lập mặc định của kernel, địa chỉ này không thể được route từ nơi khác. Service bind vào đây chỉ có thể được truy cập từ chính server đó, không phải từ Internet, ngay cả khi firewall cho phép port. Dòng Postgres ở trên mặc định là an toàn. Ngoại lệ là thiết lập kernel có tên route_localnet. Thiết lập này mặc định bị tắt, nhưng một số tool có thể bật nó, chẳng hạn kube-proxy của Kubernetes. Khi thiết lập này được bật và có thêm rule routing hoặc NAT phù hợp, traffic loopback có thể đi vào từ bên ngoài. sysctl -a | grep route_localnet phải hiển thị = 0 trên mọi dòng.

Quy tắc thực tế được suy ra trực tiếp từ đây: database, cache hoặc admin panel chỉ được các ứng dụng của bạn sử dụng nên bind vào 127.0.0.1, không phải 0.0.0.0. Nếu service không listen trên địa chỉ public, attacker không có điểm để truy cập.

Listen không đồng nghĩa với có thể truy cập

Có thêm một điểm khác biệt giúp tránh nhiều nhầm lẫn. Một port mở trên máy, tức có chương trình đang listen, khác với việc port đó có thể được truy cập từ bên ngoài, tức firewall cho phép traffic đi qua. Cả hai điều kiện đều phải đúng thì remote client mới kết nối được. Hai lỗi này cũng biểu hiện khác nhau ở phía client: kết nối bị từ chối thường có nghĩa là không có chương trình nào đang listen, còn kết nối bị treo rồi timeout thường có nghĩa là firewall đã drop packet. Đây chính là điều hai lỗi SSH đó đang cho bạn biết.

Vì vậy có hai lớp kiểm soát. Bạn quyết định service nào listen bằng cách đặt bind address cho từng service. Bạn cũng quyết định bên ngoài có thể truy cập gì bằng firewall. Một server được vận hành đúng nên dùng cả hai: service chỉ bind vào nơi cần thiết, còn firewall deny mọi thứ mà bạn chưa allow rõ ràng. Đọc danh sách service đang listen bằng ss là bước 1. Xác định firewall cho phép gì là bước 2, được trình bày trong UFW cơ bản cho firewall.

Có một điểm tinh tế thường gây lỗi. IPv4 và IPv6 là hai hệ thống riêng biệt. Firewall chỉ áp dụng cho IPv4 sẽ để các service [::] mở trên IPv6. Bẫy cụ thể này được trình bày trong bài viết riêng: bẫy firewall IPv6.

FAQ

Làm cách nào để xem các port đang mở trên Linux server?

Chạy sudo ss -tlnp cho TCP hoặc sudo ss -ulnp cho UDP. Lệnh này liệt kê mọi socket đang listen, port, địa chỉ local mà socket bind vào và process sở hữu socket đó. Đọc cột Local Address: 0.0.0.0 hoặc [::] nghĩa là service được expose ra network, còn 127.0.0.1 nghĩa là service chỉ listen trên chính máy đó.

0.0.0.0 và 127.0.0.1 khác nhau như thế nào?

0.0.0.0 nghĩa là "listen trên mọi địa chỉ IPv4", bao gồm cả địa chỉ public, nên service có thể được truy cập từ network. 127.0.0.1 là loopback, địa chỉ máy dùng để giao tiếp với chính nó. Theo thiết lập mặc định của kernel, địa chỉ này không thể được route từ nơi khác, nên service bind vào đó chỉ có thể được truy cập local. Hãy bind các service nội bộ vào 127.0.0.1 để chúng không xuất hiện trên network.

Tôi có cần mở port trong firewall để service hoạt động không?

Chỉ cần với các service phải được truy cập từ máy khác. Service bind vào 127.0.0.1 không cần allow rule, vì theo thiết lập mặc định của kernel, bên ngoài không thể truy cập service đó. Service dùng 0.0.0.0 hoặc [::] cần allow rule sau khi firewall của bạn mặc định deny traffic đi vào, và đây là thiết lập nên dùng. Nếu không có firewall hoạt động hoặc policy của firewall cho phép mọi traffic, service đó đã có thể được truy cập mà không cần rule nào.

TCP port và UDP port khác nhau như thế nào?

TCP hướng kết nối và được phần lớn service sử dụng, chẳng hạn SSH, web server và database. UDP không hướng kết nối và được dùng cho DNS cùng một số VPN. Cùng một số port ở TCP và UDP là các port riêng biệt, nên 53/tcp và 53/udp là hai port khác nhau. Khi viết firewall rule, bạn phải chỉ rõ protocol, ví dụ 22/tcp.