Port là gì và cách kiểm tra service đang listen
Tìm hiểu bản chất của port và cách dùng lệnh ss để kiểm tra các service đang listen trên Linux. Phân biệt rõ port local và port public trên VPS của bạn.
Bản chất của port là gì
Port là một con số cho phép một server chạy nhiều dịch vụ cùng lúc mà không bị lẫn lộn traffic. VPS của bạn có một địa chỉ IP, nhưng nó có thể chạy một web server, một SSH server và một database cùng một lúc. Khi một packet đến, hệ điều hành cần biết nó dành cho dịch vụ nào. Số port chính là câu trả lời. Traffic web đi đến port 443, SSH đi đến port 22. Địa chỉ IP đưa packet đến server của bạn; port đưa nó đến đúng chương trình trên server đó.
Port là một số 16-bit: 16 bit cho ra giá trị từ 0 đến 65535, và số 0 được dành riêng, nên thực tế các port chạy từ 1 đến 65535. Các port dưới 1024 là các port "well-known" và cần quyền root để mở, đó là lý do các dịch vụ tiêu chuẩn nằm ở đó: 22 cho SSH, 80 cho HTTP, 443 cho HTTPS, 53 cho DNS. Mọi thứ trên 1024 đều dành cho các chương trình thông thường.
Có hai loại là TCP và UDP, và số port trong loại này tách biệt với cùng số đó ở loại kia. TCP là giao thức dựa trên kết nối (connection-based) mà hầu hết các dịch vụ sử dụng, như SSH, HTTP và các database. UDP là giao thức không kết nối (connectionless) và được dùng cho những thứ như DNS và một số VPN. Khi bạn mở firewall, bạn thường phải chỉ định loại nào, ví dụ 22/tcp.
Listening nghĩa là một chương trình đang chờ trên một port
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 port. Từ thời điểm đó, port đó được mở trên máy và chương trình sẽ trả lời bất cứ thứ gì đến đó, tùy thuộc vào firewall. Một port không có gì đang listen sẽ đơn giản là từ chối các kết nối. Vì vậy, câu hỏi đầu tiên trong bất kỳ đợt kiểm tra bảo mật nào là: cái gì đang listen, và ở đâu.
Lệnh để trả lời câu hỏi đó là ss:
sudo ss -tlnpCác flag có nghĩa là TCP (t), chỉ các listening sockets (l), port dạng số (n, nên bạn sẽ thấy 22 thay vì ssh), và process sở hữu nó (p). Một kết quả điển hình:
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 nginxCột Process cho bạn biết chương trình nào sở hữu mỗi port, đó là cách bạn truy vết một thứ gì đó mà bạn không cố ý để nó chạy.
Cột Local Address là phần quan trọng nhất
Hãy đọc kỹ địa chỉ đứng trước mỗi port, vì nó quyết định ai có thể truy cập dịch vụ. Có ba trường hợp bạn sẽ thấy liên tục.
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. Dịch vụ có thể truy cập được từ internet qua IPv4, nếu firewall cho phép.
[::]:80 nghĩa là điều tương tự cho IPv6: listen trên mọi địa chỉ IPv6, bao gồm cả public. Nhiều chương trình bind vào đây theo mặc định, và trên Linux, một socket :: thường chấp nhận cả IPv4.
127.0.0.1:5432 nghĩa là "chỉ listen trên loopback." 127.0.0.1 là địa chỉ mà một máy dùng để tự nói chuyện với chính nó, và nó không thể định tuyến (routable) từ bất kỳ nơi nào khác. Một dịch vụ bind ở đây chỉ có thể truy cập được từ chính server đó, không bao giờ từ internet, bất kể firewall của bạn nói gì. Dòng Postgres ở trên là an toàn nhờ cấu trúc này.
Quy tắc thực tế rút ra từ điều này là: một database, một cache, hoặc một admin panel mà chỉ các ứng dụng của riêng bạn sử dụng nên bind vào 127.0.0.1, chứ không phải 0.0.0.0. Nếu nó không bao giờ listen trên một địa chỉ public, sẽ không có gì để kẻ tấn công có thể tiếp cận.
Listening không giống với reachable
Một sự phân biệt nữa giúp tránh nhiều nhầm lẫn. Một port đang mở trên máy, nghĩa là một chương trình đang listen, khác với việc port đó có thể truy cập được (reachable) từ bên ngoài, nghĩa là firewall cho phép nó. Cả hai phải cùng đúng thì một client từ xa mới có thể kết nối.
Vì vậy có hai lớp kiểm soát. Bạn quyết định cái gì listen bằng cách thiết lập bind address của mỗi dịch vụ. Và bạn quyết định thế giới bên ngoài có thể truy cập được cái gì bằng một firewall. Một server được quản lý tốt sử dụng cả hai: các dịch vụ chỉ bind ở nơi chúng cần, và một firewall chặn tất cả những gì bạn không cho phép một cách rõ ràng. Đọc những gì đang listen bằng ss là bước một; quyết định firewall cho phép những gì là bước hai, được đề cập trong firewalls 101 với UFW.
Có một chi tiết nhỏ dễ gây sai sót ở đây. IPv4 và IPv6 là riêng biệt, và một firewall chỉ bao phủ IPv4 sẽ để các dịch vụ [::] bị hở trên IPv6. Cái bẫy cụ thể đó có bài viết riêng: the IPv6 firewall trap.
FAQ
Làm thế nào để tôi xem các port nào đang mở trên Linux server của mình?
Chạy sudo ss -tlnp cho TCP hoặc sudo ss -ulnp cho UDP. Việc đó sẽ liệt kê mọi listening socket, port, địa chỉ local mà nó được bind vào, và process sở hữu nó. Đọc cột Local Address: 0.0.0.0 hoặc [::] nghĩa là dịch vụ đang lộ diện ra mạng, trong khi 127.0.0.1 nghĩa là nó chỉ listen trên chính máy đó.
Sự khác biệt giữa 0.0.0.0 và 127.0.0.1 là gì?
0.0.0.0 nghĩa là "listen trên tất cả các địa chỉ IPv4," bao gồm cả địa chỉ public, nên dịch vụ có thể được truy cập từ mạng. 127.0.0.1 là loopback, địa chỉ mà máy dùng để tự nói chuyện với chính nó, và nó không thể định tuyến từ bất kỳ nơi nào khác, nên một dịch vụ bind vào nó chỉ có thể truy cập được cục bộ. Hãy bind các dịch vụ nội bộ vào 127.0.0.1 để chúng không bao giờ bị lộ.
Tôi có cần mở port trong firewall để một dịch vụ hoạt động không?
Chỉ đối với các dịch vụ cần phải được truy cập từ các máy khác. Một dịch vụ bind vào 127.0.0.1 không cần rule firewall vì không có gì từ bên ngoài có thể chạm tới nó. Một dịch vụ trên 0.0.0.0 hoặc [::] cần một rule firewall để cho phép traffic, và nên bị chặn theo mặc định cho đến khi bạn thêm rule.
Sự khác biệt giữa một TCP port và một UDP port là gì?
TCP dựa trên kết nối và được sử dụng bởi hầu hết các dịch vụ, như SSH, web server và database. UDP không kết nối và được dùng bởi DNS và một số VPN. Cùng một số trong TCP và UDP là các port riêng biệt, nên 53/tcp và 53/udp là khác nhau. Khi bạn viết các firewall rules, bạn phải chỉ định protocol, ví dụ 22/tcp.