Tại Sao Bảo Mật SSH Phải Là Ưu Tiên Số 1 Trong 2026
SSH — Secure Shell — chính là cánh cửa chính vào mọi máy chủ Linux. Và thật lòng mà nói, kẻ tấn công luôn nhắm vào cánh cửa chính trước tiên. Các cuộc tấn công brute-force nhắm vào SSH vẫn chiếm tỷ lệ lớn kinh ngạc trong tổng số nỗ lực xâm nhập hệ thống Linux. Với hơn 5.530 CVE được ghi nhận trên nhân Linux trong năm 2025 — tăng 28% so với năm trước — và Linux đang gánh gần 50% khối lượng công việc đám mây toàn cầu, việc gia cố SSH không còn là "nên làm" nữa. Nó là bắt buộc.
Nhưng năm 2026 mang đến nhiều thứ mới hơn bạn tưởng. OpenSSH 10.0 đã ra mắt vào tháng 4/2025 với những thay đổi thực sự mang tính bước ngoặt: mã hóa hậu lượng tử trở thành mặc định, DSA bị loại bỏ hoàn toàn, và kiến trúc xác thực được tách biệt để thu hẹp bề mặt tấn công. Bên cạnh đó, xác thực bằng khóa phần cứng FIDO2 đang nhanh chóng trở thành tiêu chuẩn mới cho môi trường doanh nghiệp.
Vậy nên, hãy cùng đi từng bước nhé. Bài viết này sẽ hướng dẫn bạn gia cố SSH trên Linux một cách toàn diện — từ cấu hình cơ bản đến triển khai mã hóa hậu lượng tử và xác thực FIDO2. Dù bạn đang quản lý một máy chủ VPS đơn lẻ hay cả trăm node trong hạ tầng đám mây, những kiến thức này đều áp dụng được ngay.
OpenSSH 10.0: Những Thay Đổi Bạn Cần Biết Ngay
Loại bỏ hoàn toàn DSA — kết thúc một kỷ nguyên
OpenSSH 10.0, phát hành ngày 9/4/2025, đã chính thức loại bỏ hoàn toàn thuật toán chữ ký DSA. Quá trình này bắt đầu từ tận năm 2015 — hơn một thập kỷ chuyển đổi. DSA vốn có những hạn chế cố hữu: giới hạn ở khóa riêng 160-bit, sử dụng SHA-1, chỉ tương đương mức bảo mật đối xứng 80-bit. Nói thẳng ra, trong bối cảnh 2026, mức bảo mật này hoàn toàn không chấp nhận được.
Nếu hệ thống của bạn vẫn đang dùng khóa DSA, thì đây là lúc phải chuyển đổi ngay — không phải tuần sau, không phải tháng sau:
# Kiểm tra xem có khóa DSA nào đang được sử dụng không
find /etc/ssh/ -name "*.pub" -exec grep -l "ssh-dss" {} \;
find ~/.ssh/ -name "*.pub" -exec grep -l "ssh-dss" {} \;
# Tạo khóa Ed25519 thay thế (khuyến nghị)
ssh-keygen -t ed25519 -a 100 -C "[email protected]"
# Hoặc RSA 4096-bit nếu cần tương thích ngược
ssh-keygen -t rsa -b 4096 -C "[email protected]"
Mã hóa hậu lượng tử trở thành mặc định
Đây có lẽ là thay đổi đáng chú ý nhất. OpenSSH 10.0 đưa thuật toán trao đổi khóa lai hậu lượng tử mlkem768x25519-sha256 lên làm mặc định. Thuật toán này kết hợp ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism) — đã được NIST phê chuẩn — với ECDH/X25519 cổ điển. Ý tưởng khá hay: ngay cả khi một trong hai thuật toán bị phá vỡ, kết nối vẫn an toàn.
Tại sao lại cần quan tâm ngay bây giờ? Hai từ: "harvest now, decrypt later" (thu hoạch bây giờ, giải mã sau). Các tác nhân cấp quốc gia rất có thể đang lưu trữ lưu lượng SSH mã hóa ngay lúc này, chờ đến khi máy tính lượng tử đủ mạnh để giải mã. Nhiều chuyên gia dự đoán điều đó có thể xảy ra vào giữa thập niên 2030 — tức là chỉ còn chưa đầy 10 năm nữa thôi.
Kiến trúc tách biệt xác thực — thu hẹp bề mặt tấn công
OpenSSH 10.0 đem đến một thay đổi kiến trúc mà mình đánh giá rất cao: tách mã xác thực người dùng thành tệp nhị phân riêng biệt gọi là sshd-auth. Trước đây, tất cả mã xác thực chạy chung không gian bộ nhớ với phần còn lại. Giờ thì giai đoạn trước xác thực (pre-authentication) — nơi xảy ra phần lớn các cuộc tấn công — có không gian địa chỉ hoàn toàn riêng.
Điều này có nghĩa là gì? Đơn giản thôi: ngay cả khi kẻ tấn công tìm được lỗ hổng trong giai đoạn trước xác thực, chúng cũng không thể dễ dàng leo thang để truy cập phần kết nối đã xác thực. Bài học rút ra từ các CVE nghiêm trọng gần đây, thực sự.
Ưu tiên mật mã mạnh hơn
OpenSSH 10.0 cũng sắp xếp lại thứ tự ưu tiên các thuật toán mật mã:
- ChaCha20/Poly1305 giữ vị trí ưu tiên cao nhất
- AES-GCM được đẩy lên trước AES-CTR cho mã hóa dữ liệu
- ECDH thay thế Diffie-Hellman trường hữu hạn (modp) làm mặc định
- Thứ tự khóa máy chủ ưu tiên Ed25519 nhờ hiệu quả vượt trội
Các Lỗ Hổng SSH Nghiêm Trọng Gần Đây — Và Bài Học Xương Máu
CVE-2025-26465 — giả mạo máy chủ qua VerifyHostKeyDNS
Vào tháng 2/2025, một lỗi logic nghiêm trọng được phát hiện trong ssh(1), ảnh hưởng các phiên bản từ 6.8p1 đến 9.9p1. Khi tùy chọn VerifyHostKeyDNS được bật, kẻ tấn công nằm trên đường truyền (on-path attacker) có thể giả mạo bất kỳ máy chủ nào. Nghe đã thấy rùng mình rồi — nó phá vỡ hoàn toàn cơ chế xác minh danh tính máy chủ.
Bài học ở đây khá rõ ràng: đừng bao giờ dựa vào VerifyHostKeyDNS như biện pháp bảo mật duy nhất. Luôn xác minh dấu vân tay máy chủ thủ công khi kết nối lần đầu, và cập nhật OpenSSH ngay khi có bản vá.
CVE-2025-26466 — tấn công DoS trước xác thực
Cũng trong tháng 2/2025, sshd(8) phiên bản 9.5p1 đến 9.9p1 bị phát hiện lỗ hổng cho phép tấn công từ chối dịch vụ trước xác thực thông qua gói SSH2_MSG_PING. Kẻ tấn công có thể ngốn hết bộ nhớ và CPU của máy chủ mà chẳng cần xác thực gì cả.
Hãy kiểm tra phiên bản OpenSSH hiện tại ngay:
# Kiểm tra phiên bản sshd
sshd -V 2>&1 || ssh -V
# Kiểm tra gói OpenSSH đã cài đặt
# Trên Ubuntu/Debian
dpkg -l | grep openssh
# Trên RHEL/CentOS/Fedora
rpm -qa | grep openssh
Gia Cố Cấu Hình SSH Cơ Bản — Nền Tảng Không Được Bỏ Qua
Trước khi lao vào những tính năng nâng cao, hãy chắc chắn nền tảng của bạn đã vững. Mình từng thấy không ít người cấu hình hậu lượng tử xong xuôi mà quên... tắt đăng nhập root. Dưới đây là cấu hình sshd_config được tối ưu cho năm 2026.
Vô hiệu hóa đăng nhập root và xác thực bằng mật khẩu
# /etc/ssh/sshd_config — Cấu hình cơ bản
# Vô hiệu hóa đăng nhập root trực tiếp
PermitRootLogin no
# Vô hiệu hóa xác thực bằng mật khẩu
PasswordAuthentication no
# Vô hiệu hóa xác thực challenge-response (bao gồm PAM keyboard-interactive)
KbdInteractiveAuthentication no
# Chỉ cho phép xác thực bằng khóa công khai
PubkeyAuthentication yes
AuthenticationMethods publickey
# Giới hạn số lần thử xác thực
MaxAuthTries 3
# Giới hạn thời gian chờ xác thực
LoginGraceTime 30
# Vô hiệu hóa các phương thức xác thực không cần thiết
HostbasedAuthentication no
PermitEmptyPasswords no
Giới hạn người dùng và nhóm được phép truy cập
# Chỉ cho phép các người dùng cụ thể
AllowUsers admin deployer
# Hoặc chỉ cho phép các nhóm cụ thể
AllowGroups ssh-users sudo
# Giới hạn số phiên đồng thời
MaxSessions 3
# Giới hạn số kết nối chưa xác thực
MaxStartups 10:30:60
Giải thích nhanh về MaxStartups 10:30:60: khi có 10 kết nối chưa xác thực, SSH bắt đầu từ chối ngẫu nhiên (random drop), xác suất tăng tuyến tính đến 30% cho đến 60 kết nối — lúc đó từ chối tất cả. Đây là biện pháp khá hiệu quả chống brute-force quy mô lớn.
Thiết lập thời gian chờ phiên
# Gửi gói keepalive mỗi 300 giây (5 phút)
ClientAliveInterval 300
# Ngắt kết nối sau 3 lần không phản hồi (15 phút tổng cộng)
ClientAliveCountMax 3
# Vô hiệu hóa TCP keepalive (dùng SSH keepalive thay thế)
TCPKeepAlive no
Vô hiệu hóa các tính năng không cần thiết
# Vô hiệu hóa chuyển tiếp X11
X11Forwarding no
# Vô hiệu hóa chuyển tiếp agent (trừ khi thực sự cần)
AllowAgentForwarding no
# Vô hiệu hóa chuyển tiếp TCP (trừ khi dùng SSH tunnel)
AllowTcpForwarding no
# Vô hiệu hóa chuyển tiếp luồng (streamlocal)
AllowStreamLocalForwarding no
# Vô hiệu hóa hiển thị banner hệ thống
PrintMotd no
# Bật phân tách quyền hạn (mặc định trong phiên bản mới)
UsePrivilegeSeparation sandbox
Kiểm tra và áp dụng cấu hình
# Kiểm tra cú pháp cấu hình trước khi khởi động lại
sudo sshd -t
# Nếu không có lỗi, khởi động lại sshd
sudo systemctl restart sshd
# QUAN TRỌNG: Giữ phiên SSH hiện tại mở,
# mở terminal mới để kiểm tra kết nối trước khi đóng phiên cũ
ssh -v user@server-ip
Mẹo từ kinh nghiệm thực tế: Luôn, luôn, luôn giữ ít nhất một phiên SSH đang hoạt động khi thay đổi cấu hình. Mình đã chứng kiến (và thú thật là từng trải qua) tình huống bị khóa khỏi máy chủ vì cấu hình mới có lỗi mà không để ý. Đừng lặp lại sai lầm đó.
Cấu Hình Mã Hóa Hậu Lượng Tử Cho SSH
Kiểm tra hỗ trợ thuật toán
Đầu tiên, hãy xem phiên bản OpenSSH của bạn có hỗ trợ các thuật toán hậu lượng tử hay chưa:
# Liệt kê tất cả thuật toán trao đổi khóa được hỗ trợ
ssh -Q kex
# Kiểm tra cụ thể ML-KEM
ssh -Q kex | grep mlkem
# Kiểm tra sntrup761 (hỗ trợ từ OpenSSH 9.0)
ssh -Q kex | grep sntrup
# Kết quả mong đợi trên OpenSSH 10.0+:
# mlkem768x25519-sha256
# [email protected]
Không thấy kết quả? Vậy là bạn cần nâng cấp OpenSSH. Tin vui là trên Ubuntu 24.04 LTS trở lên, OpenSSH 9.7+ đã có sẵn. Trên RHEL 10, cả hai thuật toán đều được hỗ trợ (dù vẫn ở dạng Technology Preview).
Cấu hình máy chủ với mã hóa hậu lượng tử
# /etc/ssh/sshd_config — Cấu hình mã hóa hậu lượng tử
# Thuật toán trao đổi khóa — ưu tiên hậu lượng tử
KexAlgorithms mlkem768x25519-sha256,[email protected],curve25519-sha256,[email protected]
# Mật mã — ưu tiên ChaCha20 và AES-GCM
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
# MAC — chỉ dùng Encrypt-then-MAC
MACs [email protected],[email protected]
# Thuật toán khóa máy chủ — ưu tiên Ed25519
HostKeyAlgorithms ssh-ed25519,[email protected],rsa-sha2-512,rsa-sha2-256
# Yêu cầu kích thước RSA tối thiểu 3072-bit
RequiredRSASize 3072
Cấu hình máy khách SSH
# ~/.ssh/config — Cấu hình máy khách
Host *
# Ưu tiên trao đổi khóa hậu lượng tử
KexAlgorithms mlkem768x25519-sha256,[email protected],curve25519-sha256
# Mật mã mạnh
Ciphers [email protected],[email protected],[email protected]
# Chỉ dùng Encrypt-then-MAC
MACs [email protected],[email protected]
# Thuật toán khóa máy chủ ưa thích
HostKeyAlgorithms ssh-ed25519,[email protected],rsa-sha2-512,rsa-sha2-256
# Ngoại lệ cho máy chủ không hỗ trợ hậu lượng tử (ví dụ: GitHub)
Host github.com
KexAlgorithms +curve25519-sha256,[email protected],diffie-hellman-group16-sha512
Xác minh kết nối hậu lượng tử
# Kết nối thử với thuật toán hậu lượng tử cụ thể
ssh -o KexAlgorithms=mlkem768x25519-sha256 user@server-ip
# Xác minh thuật toán đang được sử dụng
ssh -v user@server-ip 2>&1 | grep "kex:"
# Kết quả mong đợi: debug1: kex: algorithm: mlkem768x25519-sha256
# Kiểm tra toàn bộ thông tin mật mã của kết nối
ssh -vv user@server-ip 2>&1 | grep -E "kex:|cipher:|mac:|compression:"
Một lưu ý nhỏ: từ OpenSSH 10.1, bạn sẽ nhận được cảnh báo khi kết nối đến máy chủ không hỗ trợ trao đổi khóa hậu lượng tử. Có thể tắt bằng WarnWeakCrypto no trong ssh_config, nhưng thay vì tắt cảnh báo, tốt hơn hết là nâng cấp máy chủ đích.
Xác Thực FIDO2 — Bảo Mật Phần Cứng Cho SSH
Tại sao FIDO2 vượt trội hơn khóa SSH truyền thống
Xác thực SSH truyền thống dựa trên khóa riêng lưu dưới dạng tệp trên máy tính. Dù có passphrase bảo vệ, khóa riêng vẫn có thể bị đánh cắp qua malware, phishing, hoặc truy cập trái phép. FIDO2 giải quyết triệt để vấn đề này:
- Khóa riêng không bao giờ rời khỏi thiết bị phần cứng — ngay cả khi máy tính bị compromised, kẻ tấn công cũng không thể sao chép khóa
- Yêu cầu xác minh vật lý: phải chạm vào thiết bị (User Presence) hoặc nhập PIN/vân tay (User Verification)
- Kháng phishing: khóa được ràng buộc với nguồn gốc (origin-bound), không thể bị lừa dùng cho máy chủ giả mạo
- Đa yếu tố tích hợp sẵn: kết hợp thứ bạn có (khóa phần cứng) + thứ bạn biết (PIN) hoặc thứ bạn là (vân tay)
Điều kiện tiên quyết
Để sử dụng FIDO2 với SSH, bạn cần chuẩn bị:
- OpenSSH phiên bản 8.2 trở lên (cả client lẫn server)
- Thiết bị FIDO2 tương thích (YubiKey 5 series, SoloKeys, Nitrokey FIDO2, Titan Security Key...)
- Thư viện libfido2 đã cài đặt
# Cài đặt libfido2 trên Ubuntu/Debian
sudo apt update
sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools -y
# Trên RHEL/Fedora
sudo dnf install libfido2 libfido2-devel fido2-tools -y
# Kiểm tra thiết bị FIDO2 đã được nhận diện
fido2-token -L
# Kết quả mẫu: /dev/hidraw3: vendor=0x1050, product=0x0407 (Yubico YubiKey)
Tạo khóa SSH FIDO2
OpenSSH hỗ trợ hai loại khóa FIDO2: ecdsa-sk và ed25519-sk (sk = security key). Khuyến nghị dùng ed25519-sk vì bảo mật tốt hơn và hiệu quả cao hơn.
# Tạo khóa ed25519-sk cơ bản (yêu cầu chạm thiết bị)
ssh-keygen -t ed25519-sk -C "fido2-key-$(hostname)-$(date +%Y%m%d)"
# Tạo khóa resident (lưu trên thiết bị — dùng được trên nhiều máy)
ssh-keygen -t ed25519-sk -O resident -C "resident-key-$(hostname)"
# Tạo khóa với yêu cầu xác minh PIN (bảo mật cao nhất)
ssh-keygen -t ed25519-sk -O resident -O verify-required -C "secure-key-$(hostname)"
# Khi được hỏi, chạm vào thiết bị FIDO2 và nhập PIN nếu cần
Giải thích nhanh các tùy chọn quan trọng:
- -O resident: Lưu khóa trực tiếp trên thiết bị FIDO2 — bạn có thể dùng khóa từ bất kỳ máy nào mà không cần mang theo tệp
- -O verify-required: Yêu cầu xác minh người dùng (PIN hoặc vân tay) mỗi lần sử dụng, không chỉ chạm đơn thuần
- -O no-touch-required: Bỏ qua yêu cầu chạm — chỉ nên dùng cho tự động hóa, không khuyến nghị cho truy cập tương tác
Triển khai khóa FIDO2 lên máy chủ
# Sao chép khóa công khai lên máy chủ
ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@server-ip
# Hoặc thêm thủ công
cat ~/.ssh/id_ed25519_sk.pub | ssh user@server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# Kiểm tra kết nối (sẽ yêu cầu chạm thiết bị)
ssh -i ~/.ssh/id_ed25519_sk user@server-ip
Khôi phục khóa resident từ thiết bị FIDO2
Một trong những ưu điểm lớn của khóa resident là khả năng khôi phục trên máy mới — rất tiện khi bạn đổi laptop hoặc cần làm việc từ máy khác:
# Tải tất cả khóa resident từ thiết bị về máy hiện tại
ssh-keygen -K
# Lệnh này sẽ tạo các tệp id_ed25519_sk_rk* trong thư mục hiện tại
# Di chuyển chúng vào ~/.ssh/
mv id_ed25519_sk_rk* ~/.ssh/
chmod 600 ~/.ssh/id_ed25519_sk_rk*
Cấu hình máy chủ để hỗ trợ FIDO2
# /etc/ssh/sshd_config — Hỗ trợ FIDO2
# Cho phép xác thực khóa công khai (bao gồm FIDO2)
PubkeyAuthentication yes
# Chấp nhận các loại khóa FIDO2
PubkeyAcceptedAlgorithms ssh-ed25519,[email protected],[email protected],rsa-sha2-512,rsa-sha2-256
# Yêu cầu xác minh người dùng cho khóa FIDO2
PubkeyAuthOptions verify-required
SSH Certificate Authentication — Vượt Qua Giới Hạn Khóa Công Khai
Vấn đề với authorized_keys truyền thống
Nếu bạn đang quản lý SSH bằng authorized_keys cho hơn vài chục máy chủ, chắc bạn đã biết đó là cơn ác mộng thế nào. Cụ thể:
- Không có thời hạn: Khóa SSH truyền thống không hết hạn — nếu bị rò rỉ, chúng hữu dụng mãi mãi
- Khó quản lý quy mô lớn: Với hàng trăm máy chủ và hàng nghìn người dùng, việc phân phối và thu hồi khóa trở thành nỗi khổ
- Không có danh tính tập trung: Mỗi máy chủ quản lý authorized_keys riêng
- Thiếu audit trail: Rất khó theo dõi ai đã truy cập vào đâu, khi nào
SSH certificates giải quyết tất cả các vấn đề trên bằng Certificate Authority (CA) tập trung.
Thiết lập SSH Certificate Authority
# Tạo CA cho khóa người dùng (user CA)
ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "User CA $(date +%Y)"
# Tạo CA riêng cho khóa máy chủ (host CA)
ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "Host CA $(date +%Y)"
# Đặt quyền truy cập nghiêm ngặt
chmod 600 /etc/ssh/ca/user_ca /etc/ssh/ca/host_ca
chmod 644 /etc/ssh/ca/user_ca.pub /etc/ssh/ca/host_ca.pub
Quan trọng: Luôn dùng CA riêng biệt cho người dùng và máy chủ. Nếu user CA bị rò rỉ, kẻ tấn công chỉ có thể tạo chứng chỉ người dùng giả — nhưng không thể giả mạo máy chủ. Phân tách rủi ro là nguyên tắc cốt lõi.
Ký chứng chỉ cho người dùng
# Ký chứng chỉ ngắn hạn cho người dùng (hết hạn sau 8 giờ)
ssh-keygen -s /etc/ssh/ca/user_ca \
-I "[email protected]$(date +%Y%m%d)" \
-n admin,deployer \
-V +8h \
-z $(date +%s) \
/home/admin/.ssh/id_ed25519.pub
# Giải thích các tùy chọn:
# -s: Khóa CA dùng để ký
# -I: Định danh chứng chỉ (cho audit log)
# -n: Danh sách principal (tên người dùng được phép)
# -V: Thời hạn hiệu lực (+8h = 8 giờ từ bây giờ)
# -z: Số serial (dùng timestamp để đảm bảo duy nhất)
# Xem thông tin chứng chỉ
ssh-keygen -L -f /home/admin/.ssh/id_ed25519-cert.pub
Ký chứng chỉ cho máy chủ
# Ký chứng chỉ cho khóa máy chủ (hết hạn sau 1 năm)
ssh-keygen -s /etc/ssh/ca/host_ca \
-I "webserver01.company.com" \
-h \
-n webserver01.company.com,10.0.1.10 \
-V +52w \
/etc/ssh/ssh_host_ed25519_key.pub
# -h: Đánh dấu đây là chứng chỉ máy chủ (không phải người dùng)
Cấu hình máy chủ tin tưởng User CA
# /etc/ssh/sshd_config — Tin tưởng CA người dùng
# Chỉ định khóa công khai của User CA
TrustedUserCAKeys /etc/ssh/ca/user_ca.pub
# Chỉ định chứng chỉ máy chủ
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
# Tùy chọn: Giới hạn principal được phép
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
# Tạo tệp principal cho mỗi người dùng
echo -e "admin\ndeployer" | sudo tee /etc/ssh/auth_principals/admin
echo "deployer" | sudo tee /etc/ssh/auth_principals/deployer
Cấu hình máy khách tin tưởng Host CA
# Thêm vào ~/.ssh/known_hosts hoặc /etc/ssh/ssh_known_hosts
echo "@cert-authority *.company.com $(cat /etc/ssh/ca/host_ca.pub)" >> ~/.ssh/known_hosts
# Giờ đây kết nối SSH sẽ tự động xác minh chứng chỉ máy chủ
# Không còn cảnh báo "unknown host key" cho các máy chủ có chứng chỉ hợp lệ
Fail2Ban Và Giám Sát SSH Nâng Cao
Cấu hình Fail2Ban cho SSH
Fail2Ban tự động chặn IP sau nhiều lần đăng nhập thất bại — tuyến phòng thủ đầu tiên chống brute-force. Cài đặt và cấu hình khá nhanh:
# Cài đặt Fail2Ban
sudo apt install fail2ban -y # Ubuntu/Debian
sudo dnf install fail2ban -y # RHEL/Fedora
# Tạo cấu hình cục bộ (không chỉnh sửa tệp gốc)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# /etc/fail2ban/jail.local — Cấu hình SSH jail
[DEFAULT]
# Thời gian cấm mặc định: 1 giờ
bantime = 3600
# Cửa sổ theo dõi: 10 phút
findtime = 600
# Số lần thử tối đa trước khi cấm
maxretry = 3
# Bật chế độ cấm tăng dần
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 86400
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# Chế độ phát hiện nâng cao (phát hiện nhiều kiểu tấn công hơn)
mode = aggressive
# Khởi động và kích hoạt Fail2Ban
sudo systemctl enable --now fail2ban
# Kiểm tra trạng thái jail SSH
sudo fail2ban-client status sshd
# Xem danh sách IP bị cấm
sudo fail2ban-client get sshd banip
# Gỡ cấm một IP cụ thể (khi cần)
sudo fail2ban-client set sshd unbanip 192.168.1.100
Giám sát SSH với auditd
Để có audit trail đầy đủ, auditd là công cụ không thể thiếu. Cấu hình sau sẽ giám sát mọi thay đổi liên quan đến SSH:
# /etc/audit/rules.d/ssh.rules — Quy tắc audit cho SSH
# Giám sát tệp cấu hình SSH
-w /etc/ssh/sshd_config -p wa -k sshd_config_change
-w /etc/ssh/ -p wa -k ssh_dir_change
# Giám sát tệp authorized_keys
-w /root/.ssh/authorized_keys -p wa -k ssh_authorized_keys
-w /home/ -p wa -k ssh_user_home
# Giám sát đăng nhập SSH
-a always,exit -F arch=b64 -S accept -F a0=22 -k ssh_connection
# Giám sát lệnh ssh-keygen
-w /usr/bin/ssh-keygen -p x -k ssh_keygen_exec
# Tải lại quy tắc audit
sudo augenrules --load
# Tìm kiếm sự kiện SSH trong audit log
sudo ausearch -k sshd_config_change --interpret
sudo ausearch -k ssh_authorized_keys --interpret
Bastion Host — Kiến Trúc Truy Cập An Toàn
Tại sao cần Bastion Host
Bastion host (hay jump server) là máy chủ trung gian duy nhất được phép nhận kết nối SSH từ Internet. Mọi kết nối đến máy chủ nội bộ đều phải đi qua đây. Nghe có vẻ bất tiện, nhưng lợi ích thì rất rõ ràng:
- Giảm bề mặt tấn công: Chỉ một điểm tiếp xúc với Internet thay vì hàng chục máy chủ
- Tập trung giám sát: Mọi kết nối SSH được ghi nhật ký tại một điểm duy nhất
- Kiểm soát truy cập: Áp dụng MFA và chính sách nghiêm ngặt tại bastion
- Phân đoạn mạng: Máy chủ nội bộ không cần IP công khai
Cấu hình SSH Jump Host
# ~/.ssh/config — Cấu hình bastion host
# Bastion host
Host bastion
HostName bastion.company.com
User admin
Port 22
IdentityFile ~/.ssh/id_ed25519_sk
ForwardAgent no
# Máy chủ nội bộ — truy cập qua bastion
Host internal-web
HostName 10.0.1.10
User deployer
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host internal-db
HostName 10.0.2.20
User dbadmin
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
# Mẫu cho tất cả máy chủ nội bộ
Host 10.0.*
ProxyJump bastion
User admin
# Kết nối thẳng đến máy chủ nội bộ (tự động qua bastion)
ssh internal-web
# Hoặc dùng cú pháp ProxyJump trực tiếp
ssh -J bastion.company.com [email protected]
Script Tự Động Kiểm Tra Cấu Hình SSH
Đây là script mình hay dùng để kiểm tra nhanh cấu hình SSH trên máy chủ. Nó không thay thế được các công cụ chuyên dụng như ssh-audit, nhưng đủ để có cái nhìn tổng quan:
#!/bin/bash
# ssh-hardening-check.sh — Kiểm tra và báo cáo cấu hình SSH
# Tương thích: Ubuntu 22.04+, RHEL 8+, Debian 12+
set -euo pipefail
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
NC="\033[0m"
SSHD_CONFIG="/etc/ssh/sshd_config"
SCORE=0
TOTAL=0
WARNINGS=()
check() {
local description="$1"
local result="$2"
TOTAL=$((TOTAL + 1))
if [ "$result" = "PASS" ]; then
echo -e " ${GREEN}[PASS]${NC} $description"
SCORE=$((SCORE + 1))
elif [ "$result" = "WARN" ]; then
echo -e " ${YELLOW}[WARN]${NC} $description"
WARNINGS+=("$description")
else
echo -e " ${RED}[FAIL]${NC} $description"
fi
}
echo "========================================="
echo " SSH Hardening Check — $(date +%Y-%m-%d)"
echo "========================================="
echo ""
# Kiểm tra phiên bản OpenSSH
SSH_VERSION=$(ssh -V 2>&1 | grep -oP "OpenSSH_\K[0-9]+\.[0-9]+")
echo "OpenSSH Version: $SSH_VERSION"
echo ""
# 1. Kiểm tra xác thực
echo "[Xác thực]"
PASS_AUTH=$(sshd -T 2>/dev/null | grep -i "^passwordauthentication" | awk "{print \$2}")
[ "$PASS_AUTH" = "no" ] && check "Password authentication disabled" "PASS" || check "Password authentication disabled" "FAIL"
ROOT_LOGIN=$(sshd -T 2>/dev/null | grep -i "^permitrootlogin" | awk "{print \$2}")
[ "$ROOT_LOGIN" = "no" ] && check "Root login disabled" "PASS" || check "Root login disabled" "FAIL"
MAX_AUTH=$(sshd -T 2>/dev/null | grep -i "^maxauthtries" | awk "{print \$2}")
[ "$MAX_AUTH" -le 3 ] 2>/dev/null && check "MaxAuthTries <= 3 (current: $MAX_AUTH)" "PASS" || check "MaxAuthTries <= 3 (current: $MAX_AUTH)" "FAIL"
echo ""
# 2. Kiểm tra mật mã
echo "[Mật mã]"
if ssh -Q kex 2>/dev/null | grep -q "mlkem768x25519"; then
check "Post-quantum KEX available (mlkem768x25519)" "PASS"
else
check "Post-quantum KEX available (mlkem768x25519)" "WARN"
fi
if ! sshd -T 2>/dev/null | grep -i "^ciphers" | grep -q "3des\|blowfish\|arcfour\|cast128"; then
check "No weak ciphers enabled" "PASS"
else
check "No weak ciphers enabled" "FAIL"
fi
echo ""
# 3. Kiểm tra tính năng bổ sung
echo "[Tính năng]"
X11_FWD=$(sshd -T 2>/dev/null | grep -i "^x11forwarding" | awk "{print \$2}")
[ "$X11_FWD" = "no" ] && check "X11 forwarding disabled" "PASS" || check "X11 forwarding disabled" "WARN"
AGENT_FWD=$(sshd -T 2>/dev/null | grep -i "^allowagentforwarding" | awk "{print \$2}")
[ "$AGENT_FWD" = "no" ] && check "Agent forwarding disabled" "PASS" || check "Agent forwarding disabled" "WARN"
echo ""
# 4. Kiểm tra Fail2Ban
echo "[Phòng thủ]"
if systemctl is-active --quiet fail2ban 2>/dev/null; then
check "Fail2Ban is running" "PASS"
else
check "Fail2Ban is running" "FAIL"
fi
echo ""
echo "========================================="
echo -e " Điểm: ${SCORE}/${TOTAL}"
PERCENT=$((SCORE * 100 / TOTAL))
if [ "$PERCENT" -ge 80 ]; then
echo -e " Đánh giá: ${GREEN}TỐT${NC} (${PERCENT}%)"
elif [ "$PERCENT" -ge 60 ]; then
echo -e " Đánh giá: ${YELLOW}TRUNG BÌNH${NC} (${PERCENT}%)"
else
echo -e " Đánh giá: ${RED}CẦN CẢI THIỆN${NC} (${PERCENT}%)"
fi
echo "========================================="
Tích Hợp Vào Pipeline DevSecOps
Kiểm tra SSH trong CI/CD
Nếu bạn đang làm DevSecOps (hoặc đang muốn bắt đầu), tích hợp kiểm tra SSH vào pipeline CI/CD là bước hợp lý tiếp theo. Mục tiêu là đảm bảo mọi máy chủ mới triển khai đều tuân thủ chính sách bảo mật từ đầu:
# .github/workflows/ssh-audit.yml
name: SSH Security Audit
on:
schedule:
- cron: "0 6 * * 1" # Mỗi thứ Hai lúc 6:00 UTC
workflow_dispatch:
jobs:
ssh-audit:
runs-on: ubuntu-latest
strategy:
matrix:
server:
- name: "web-prod-01"
host: "10.0.1.10"
- name: "db-prod-01"
host: "10.0.2.20"
steps:
- name: Install ssh-audit
run: pip install ssh-audit
- name: Audit SSH configuration
run: |
ssh-audit --json ${{ matrix.server.host }} > audit-${{ matrix.server.name }}.json
# Kiểm tra lỗi nghiêm trọng
if jq -e ".errors | length > 0" audit-${{ matrix.server.name }}.json; then
echo "FAIL: SSH audit found critical issues on ${{ matrix.server.name }}"
jq ".errors" audit-${{ matrix.server.name }}.json
exit 1
fi
- name: Upload audit results
uses: actions/upload-artifact@v4
with:
name: ssh-audit-${{ matrix.server.name }}
path: audit-${{ matrix.server.name }}.json
Ansible playbook cho gia cố SSH hàng loạt
# ssh-hardening.yml — Ansible Playbook
---
- name: SSH Hardening
hosts: all
become: true
vars:
ssh_port: 22
ssh_max_auth_tries: 3
ssh_client_alive_interval: 300
ssh_client_alive_count_max: 3
tasks:
- name: Ensure OpenSSH is up to date
ansible.builtin.package:
name: openssh-server
state: latest
- name: Deploy hardened sshd_config
ansible.builtin.template:
src: templates/sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: "0600"
validate: "sshd -t -f %s"
notify: Restart sshd
- name: Ensure only Ed25519 and RSA host keys exist
ansible.builtin.file:
path: "/etc/ssh/ssh_host_{{ item }}_key"
state: absent
loop:
- dsa
- ecdsa
notify: Restart sshd
- name: Configure Fail2Ban for SSH
ansible.builtin.template:
src: templates/fail2ban-sshd.j2
dest: /etc/fail2ban/jail.d/sshd.local
owner: root
group: root
mode: "0644"
notify: Restart fail2ban
handlers:
- name: Restart sshd
ansible.builtin.service:
name: sshd
state: restarted
- name: Restart fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted
Checklist Bảo Mật SSH 2026 — Lưu Lại Để Dùng Dần
Tổng hợp lại tất cả, đây là checklist bạn nên kiểm tra định kỳ cho mọi máy chủ SSH:
| Hạng mục | Kiểm tra | Mức độ |
|---|---|---|
| Phiên bản | OpenSSH 10.0+ đã cài đặt | Quan trọng |
| Xác thực | Vô hiệu hóa mật khẩu, chỉ dùng khóa/chứng chỉ | Quan trọng |
| Root | PermitRootLogin no | Quan trọng |
| Mã hóa | Hậu lượng tử KEX làm mặc định | Cao |
| Khóa máy chủ | Chỉ Ed25519, loại bỏ DSA/ECDSA | Cao |
| Cipher | ChaCha20/AES-GCM, không có cipher yếu | Cao |
| FIDO2 | Triển khai cho tài khoản quản trị | Khuyến nghị |
| Chứng chỉ | SSH CA cho môi trường 10+ máy chủ | Khuyến nghị |
| Fail2Ban | Đang chạy với chế độ aggressive | Quan trọng |
| Audit | auditd giám sát thay đổi cấu hình SSH | Cao |
| Bastion | Jump host cho truy cập nội bộ | Khuyến nghị |
| Tự động hóa | Kiểm tra SSH trong CI/CD pipeline | Khuyến nghị |
Lời Kết
Bảo mật SSH không phải là việc cấu hình một lần rồi quên đi — mình muốn nhấn mạnh điều này. Đó là quá trình liên tục đòi hỏi cập nhật, giám sát và thích ứng với các mối đe dọa mới. Năm 2026 đánh dấu bước ngoặt quan trọng khi mã hóa hậu lượng tử chính thức trở thành tiêu chuẩn trong OpenSSH 10.0.
Đừng chờ đến khi máy tính lượng tử trở thành hiện thực mới hành động.
Nếu bạn chỉ có thể làm ba việc ngay bây giờ, hãy làm ba việc này: nâng cấp lên OpenSSH 10.0+, vô hiệu hóa xác thực bằng mật khẩu, và bật Fail2Ban. Ba bước đơn giản này sẽ loại bỏ phần lớn các cuộc tấn công SSH phổ biến. Từ đó, dần dần triển khai FIDO2, SSH certificates, và tích hợp kiểm tra bảo mật vào pipeline DevSecOps để đạt mức bảo mật toàn diện hơn.
Bài viết này nối tiếp tự nhiên loạt bài về bảo mật Linux — sau khi đã nắm vững các công cụ kiểm tra với Lynis, OpenSCAP và CIS Benchmarks, giờ bạn đã có đủ kiến thức để gia cố cánh cửa quan trọng nhất vào hệ thống của mình.