Làm cho SSH trở nên vô hình: Bảo mật máy chủ với Single Packet Authorization (SPA) và fwknop

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Cuộc gọi đánh thức lúc 2:14 sáng

Thứ Ba tuần trước, điện thoại của tôi bắt đầu reo inh ỏi lúc 2:14 sáng. Tôi lết mình đến bàn làm việc, nheo mắt nhìn vào màn hình terminal khi các dòng log từ một production jump host đổ về dồn dập. Một botnet đã đánh hơi được một cổng SSH tạm thời mà tôi vừa mở cho một cộng tác viên. Chỉ trong vài phút, tệp /var/log/auth.log đã phình to với tốc độ 50 lần thử đăng nhập mỗi giây. Ngay cả khi đã áp dụng xác thực bằng khóa công khai (public key), việc chứng kiến một hệ thống đang chạy thực tế (production) phải chịu đựng kiểu dò quét dồn dập như vậy là quá đủ để làm hỏng một đêm của bất kỳ quản trị viên hệ thống nào.

Thay đổi cổng mặc định từ 22 sang một số cao như 49221 là bước đầu tiên thường thấy. Nhưng hãy thực tế đi: các công cụ như Masscan có thể quét toàn bộ dải địa chỉ IPv4 với tốc độ 25 triệu gói tin mỗi giây. “Bảo mật bằng cách ẩn mình” (Security through obscurity) là một chiến lược mong manh, dễ dàng sụp đổ ngay khi gặp phải một trình quét chuyên dụng. Tôi không chỉ muốn đổi cổng. Tôi muốn nó trở nên vô hình — hoàn toàn không tồn tại đối với internet công cộng, nhưng lại có thể truy cập ngay lập tức khi tôi cần.

Vấn đề cốt lõi: Những “ngọn hải đăng” kỹ thuật số

Các dịch vụ mạng tiêu chuẩn yêu cầu một cổng phải ở trạng thái ‘Open’ (Mở) hoặc ‘Listening’ (Đang lắng nghe) để chấp nhận kết nối. Trạng thái này giống như một ngọn hải đăng. Ngay cả khi bạn sử dụng Fail2Ban để chặn IP sau ba lần thử sai, cổng đó vẫn phản hồi gói tin SYN. Điều này cho kẻ tấn công biết chính xác dịch vụ bạn đang chạy là gì. Nếu một lỗ hổng zero-day như ‘regreSSHion’ (CVE-2024-6387) xuất hiện, một cổng hiển thị rõ ràng sẽ trở thành một mối nguy cơ trước khi bạn kịp uống xong tách cà phê sáng và chạy lệnh apt upgrade.

So sánh các bức tường: Port Knocking vs. SPA

Tôi bắt đầu bằng việc đánh giá tiêu chuẩn hiện tại của đội ngũ. Xác thực bằng khóa (Key Auth) và Fail2Ban rất tuyệt, nhưng chúng không giúp ẩn dịch vụ. Đầu tiên tôi xem xét Port Knocking. Đó là một thủ thuật cổ điển: tường lửa sẽ luôn đóng cho đến khi nó phát hiện một chuỗi các nỗ lực kết nối cụ thể — ví dụ như truy cập vào cổng 7000, sau đó là 8000, rồi đến 9000. Chỉ khi đó, nó mới mở cổng 22 cho địa chỉ IP của bạn.

Điểm yếu là gì? Port knocking dễ bị tấn công nghe lén gói tin (packet sniffing). Nếu kẻ tấn công nằm trên đường truyền mạng, họ có thể thấy “mật mã gõ cửa” và phát lại nó để giành quyền truy cập. Nó cũng nổi tiếng là hoạt động chập chờn trên các mạng di động không ổn định, nơi các gói tin thường đến sai thứ tự, khiến bạn bị khóa ngoài máy chủ của chính mình.

Cuối cùng, tôi chọn Single Packet Authorization (SPA). Khác với port knocking, SPA sử dụng một gói tin duy nhất, đã được mã hóa và không thể phát lại (non-replayable). Nó không dựa trên một chuỗi các nỗ lực kết nối. Thay vào đó, một daemon chạy ngầm sẽ giám sát đường truyền qua libpcap, tìm kiếm một gói tin UDP được định dạng đặc biệt. Khi phát hiện, daemon sẽ giải mã gói tin, xác minh chữ ký và cập nhật tường lửa (iptables/nftables) một cách linh hoạt cho riêng IP của bạn trong vài giây.

Giải pháp: Triển khai fwknop

Tôi chọn fwknop (FireWall Knock Operator) vì đây là tiêu chuẩn công nghiệp cho SPA. Nó sử dụng mã hóa Rijndael (AES) hoặc GnuPG, khiến kẻ tấn công hầu như không thể giả mạo hoặc phát lại lệnh kích hoạt ủy quyền.

1. Cấu hình phía máy chủ

Tôi bắt đầu bằng việc cài đặt thành phần máy chủ trên một máy Ubuntu. Ưu tiên hàng đầu của tôi là đảm bảo chính sách mặc định cho chuỗi INPUT được đặt thành DROP cho cổng 22.

sudo apt update
sudo apt install fwknop-server iptables-persistent

Cấu hình yêu cầu hai khóa: một khóa mã hóa mạnh và một khóa Mã xác thực thông điệp dựa trên băm (HMAC). Để tạo các khóa này, tôi đã sử dụng trình tạo tại toolcraft.app/vi/tools/security/password-generator. Nó chạy cục bộ trên trình duyệt, vì vậy không có dữ liệu nhạy cảm nào bị gửi lên mạng. Tôi đã tạo hai chuỗi 64 ký tự cho việc thiết lập.

Tiếp theo, tôi định nghĩa các quy tắc truy cập trong /etc/fwknop/access.conf:

SOURCE                     ANY
OPEN_PORTS                 tcp/22
KEY                        YOUR_LONG_ENCRYPTION_KEY
HMAC_KEY                   YOUR_LONG_HMAC_KEY
FW_ACCESS_TIMEOUT          30

Cuối cùng, tôi cấu hình /etc/fwknop/fwknopd.conf để lắng nghe trên giao diện mạng chính xác, thường là eth0 hoặc ens3:

PCAP_INTF                  eth0

2. Thiết lập phía máy khách

Trên máy cục bộ của mình, tôi cài đặt client fwknop và lưu thông tin đăng nhập để tránh việc phải gõ lại nhiều lần.

# Trên máy cục bộ của bạn
fwknop -A tcp/22 -D [Server_IP] --key-gen --use-hmac --save-rc-stanza

Lệnh này sẽ tạo một mục nhập trong ~/.fwknoprc. Tôi đã cập nhật thủ công các khóa 64 ký tự đã tạo trước đó vào tệp này.

3. Kiểm tra khả năng “ngụy trang”

Khi fwknopd đang chạy và tường lửa đang chặn (drop) lưu lượng truy cập cổng 22, tôi đã thử thực hiện một kết nối SSH thông thường. Nó bị treo vô thời hạn. Hoàn hảo. Đối với một trình quét, máy chủ này trông như đã chết.

Sau đó, tôi gửi gói tin SPA:

fwknop -n my-production-server

Client đã xác nhận việc truyền tin. Chỉ trong vài mili giây, fwknopd đã chặn gói tin UDP (thường ở cổng 62201), xác minh các khóa và chèn một quy tắc iptables tạm thời cho IP công cộng hiện tại của tôi.

ssh user@server_ip

Tôi đã vào được. Tệp /var/log/auth.log hoàn toàn im ắng. Không có tiếng ồn từ brute force, không có trình quét, chỉ là một kết nối sạch sẽ.

Bảo mật vận hành trong thực tế

Chuyển sang SPA đã tạo ra sự khác biệt một trời một vực đối với mức độ căng thẳng khi trực hệ thống (on-call) của tôi. Có hai bài học rút ra. Thứ nhất, luôn duy trì một đường truy cập ‘khẩn cấp’ dự phòng, chẳng hạn như bảng điều khiển (console) của nhà cung cấp đám mây, đề phòng trường hợp tiến trình fwknopd bị lỗi. Thứ hai, hãy nhớ rằng SPA là một lớp giáp bổ sung, chứ không phải là sự thay thế cho SSH key. Tôi vẫn sử dụng khóa Ed25519 với mật khẩu (passphrase) mạnh. Điểm khác biệt là giờ đây cổng SSH của tôi là một ‘hố đen’ đối với internet cho đến khi tôi quyết định cho phép chính mình đi vào.

Share: