Linux服务器安全加固实战:从Telnet到SSH与防火墙配置
1. 项目概述:从Telnet到SSH的演进与防火墙的必要性
在Linux运维和网络管理的日常工作中,远程管理服务器是再基础不过的操作。十几年前,我接触的第一台Linux服务器,用的就是Telnet。敲下telnet 192.168.1.100,输入用户名密码,就能在千里之外操作它,那种感觉在当时很神奇。但很快,师傅就严肃地告诉我:“生产环境绝对不能用Telnet,数据全是明文传输,跟在大街上喊密码没区别。” 这句话我记到现在。今天,我们就来深入聊聊Linux网络安全的基石:如何告别不安全的Telnet,全面拥抱SSH,并构筑起坚固的防火墙防线。这不仅是命令的堆砌,更是一套完整的安全思维和实战体系,适合所有从Linux新手到希望夯实安全基础的运维人员。
简单来说,这个“项目”的核心就是实现Linux服务器的安全远程访问与网络边界防护。它要解决的核心问题是:如何确保管理员能够方便地远程管理服务器,同时杜绝敏感信息(如密码、操作指令)在传输过程中被窃听,并有效控制哪些网络流量可以进出服务器。我们将围绕Telnet的风险、SSH的全面配置与加固,以及如何使用iptables或firewalld构建灵活的防火墙策略来展开。你会发现,安全的配置并非高深莫测,而是一系列明确、可实操的选择和设置。
2. 核心组件深度解析:协议、服务与工具
2.1 Telnet:为何成为历史遗留的风险点
Telnet协议设计于互联网的“蛮荒时代”,其核心问题在于所有通信内容,包括用户名和密码,均以明文形式在网络中传输。这意味着,任何一个能够截获你与服务器之间数据包的人(比如在同一局域网内发起ARP欺骗攻击),都可以轻而易举地看到你的登录凭证和后续的所有操作命令。
除了明文传输这个致命伤,Telnet服务本身通常也缺乏现代认证机制(如公钥认证)和强大的加密会话支持。虽然在某些极端封闭、物理隔离的网络环境中,可能因为老旧设备兼容性问题而短暂使用,但在任何对安全有基本要求的场景下,启用Telnet服务等同于敞开大门。
在Linux中,Telnet通常作为一个独立的软件包提供。例如,在基于RPM的系统中,你可能看到telnet-server包;在基于Debian的系统中,则是telnetd。检查系统是否安装了Telnet服务端,是安全自查的第一步。你可以使用rpm -qa | grep telnet或dpkg -l | grep telnet来查看。如果发现,除非有无法替代的特定理由,否则我们的第一个操作就是卸载它:sudo yum remove telnet-server或sudo apt purge telnetd。
2.2 SSH:安全远程管理的基石
SSH(Secure Shell)协议彻底解决了Telnet的问题。它通过非对称加密技术建立安全连接,整个过程可以概括为:
- 版本协商与密钥交换:客户端连接服务器时,双方先协商使用的SSH协议版本和加密算法。
- 服务器身份验证:服务器将自己的公钥发送给客户端。客户端首次连接时会看到该公钥的指纹,并选择是否信任(这就是你第一次连接时看到的“The authenticity of host ... can't be established”提示的由来)。此后,客户端会将该公钥保存在
~/.ssh/known_hosts文件中,下次连接时用于验证服务器身份,防止“中间人攻击”。 - 用户身份验证:服务器身份确认后,开始验证登录用户。常见方式有:
- 密码认证:密码被加密后传输,但仍有被暴力破解的风险。
- 公钥认证:最推荐的方式。客户端生成一对密钥(私钥自己保管,公钥上传到服务器)。登录时,客户端用私钥签名一段挑战信息,服务器用预留的公钥验证。这种方式无需传输密码,且破解难度极高。
- 会话加密:认证通过后,双方会利用之前协商的对称加密算法(如AES)对后续所有通信数据进行加密,确保传输内容的机密性。
Linux世界最主流的SSH实现是OpenSSH。它包含了服务端(sshd)和客户端(ssh)工具。我们接下来的配置将主要围绕OpenSSH展开。
2.3 防火墙:网络流量的守门人
防火墙是部署在网络边界,根据预定义的安全规则,对进出网络的数据包进行过滤、控制的系统。在Linux中,我们主要接触两类防火墙工具:
- iptables:历史悠久的经典工具,它直接与内核的Netfilter框架交互,功能强大且直接,但规则语法相对复杂,且规则在重启后默认会丢失(需另存或使用持久化工具)。
- firewalld:Red Hat系列发行版(如CentOS、RHEL、Fedora)引入的动态防火墙管理器。它提供了更高级的抽象(如“区域”、“服务”概念),支持运行时动态更新规则而无需重启服务,且配置默认持久化。对于新手和大多数常规应用场景,
firewalld更友好。
无论是iptables还是firewalld,其核心工作都是基于对数据包的五元组(源IP、目标IP、源端口、目标端口、协议)以及连接状态进行分析,然后执行ACCEPT(接受)、DROP(丢弃,无响应)或REJECT(拒绝,返回拒绝响应)等动作。
3. 实战配置:从安装加固到策略部署
3.1 SSH服务端深度配置与加固
默认安装的SSH虽然安全,但仍有优化和加固空间。配置文件通常位于/etc/ssh/sshd_config。修改前务必备份!以下是一些关键配置项及其解读:
# 使用vim或nano编辑配置文件 sudo vim /etc/ssh/sshd_config基础安全加固:
# 1. 修改默认端口:将22端口改为一个大于1024的非知名端口,能减少大量自动化扫描和暴力破解尝试。 Port 2222 # 示例端口,请自定义一个 # 2. 禁止root用户直接登录:即使密码再复杂,直接暴露root也是高风险。 PermitRootLogin no # 3. 限制用户登录:只允许必要的用户通过SSH登录。 AllowUsers alice bob admin_user # 4. 禁用密码认证,强制使用公钥认证(前提是你已配置好公钥)。 PasswordAuthentication no PubkeyAuthentication yes # 5. 使用更安全的协议版本,禁用已过时且存在漏洞的SSHv1。 Protocol 2 # 6. 限制最大认证尝试次数,减缓暴力破解。 MaxAuthTries 3 # 7. 设置空闲会话超时断开,避免连接被长期挂起。 ClientAliveInterval 300 # 300秒发送一次保活消息 ClientAliveCountMax 2 # 连续2次无响应则断开连接配置后必须重启服务:
sudo systemctl restart sshd # 检查服务状态和是否有错误日志 sudo systemctl status sshd sudo journalctl -u sshd -f --since "5 minutes ago"重要提示:在禁用密码认证和修改端口前,必须确保你的公钥认证已经在该服务器上配置成功并能正常登录。否则,你会把自己锁在门外!测试时,建议保持两个SSH会话窗口,一个用于修改配置并重启服务,另一个用于测试新配置是否生效,确认无误后再关闭旧会话。
3.2 生成与部署SSH密钥对
这是告别密码,实现免密安全登录的关键步骤。
在客户端机器上生成密钥对(如果还没有):
ssh-keygen -t ed25519 -C "your_email@example.com" # -t 指定密钥类型,ed25519比传统的rsa更安全快速。也可用 `-t rsa -b 4096` # 执行后会提示你输入密钥保存路径(直接回车用默认路径 ~/.ssh/id_ed25519)和密码短语(passphrase)。密码短语为私钥再加一层保护,即使私钥文件泄露,没有短语也无法使用。将公钥部署到目标服务器:
# 最简单的方法,使用 ssh-copy-id 工具 ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub username@server_ip # -p 指定SSH端口(如果你修改了默认端口) # -i 指定要上传的公钥文件 # 如果服务器没有 ssh-copy-id,可以手动操作: # 1. 将公钥内容复制到剪贴板 cat ~/.ssh/id_ed25519.pub # 2. 登录服务器,编辑 ~/.ssh/authorized_keys 文件,将公钥内容粘贴进去一行。 # 3. 确保 .ssh 目录权限为700,authorized_keys文件权限为600。3.3 使用firewalld配置防火墙策略
我们以firewalld为例,因为它更直观且易于管理。首先确保firewalld已安装并运行:
sudo systemctl status firewalld # 如果未运行,启用并启动:sudo systemctl enable --now firewalld核心概念与操作:
- 区域(Zone):预定义的规则集,如
public(公共区域,默认)、internal(内部网络)、trusted(信任所有流量)等。网卡可以被绑定到不同区域。 - 服务(Service):预定义的一组端口/协议组合,如
ssh(默认22端口)、http(80端口)、https(443端口)。
基础配置步骤:
查看默认区域和活跃区域:
sudo firewall-cmd --get-default-zone sudo firewall-cmd --get-active-zones为SSH开放自定义端口(例如我们改成的2222):
# 方法一:将现有ssh服务的端口修改为2222(更规范) sudo firewall-cmd --permanent --remove-service=ssh # 先移除默认22端口 sudo firewall-cmd --permanent --new-service=ssh-custom # 创建自定义服务(可选) sudo firewall-cmd --permanent --service=ssh-custom --add-port=2222/tcp --set-description="Custom SSH Port" sudo firewall-cmd --permanent --add-service=ssh-custom # 方法二:直接添加端口(更直接) sudo firewall-cmd --permanent --add-port=2222/tcp限制SSH访问源IP(强烈建议):如果管理员的IP地址是固定的,可以将其加入白名单,极大提升安全性。
# 假设管理员IP是 203.0.113.10 sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="2222" protocol="tcp" accept' # 然后,拒绝其他所有IP访问2222端口(注意:默认策略是拒绝,如果已添加了--add-port,则需要先移除或使用富规则设置拒绝) # 更清晰的做法:先移除对公网开放的2222端口规则,然后只添加允许特定IP的规则。 sudo firewall-cmd --permanent --remove-port=2222/tcp # 移除之前的通用开放规则 sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="2222" protocol="tcp" accept'应用配置并检查:
sudo firewall-cmd --reload # 重新加载配置,使永久规则生效 sudo firewall-cmd --list-all # 列出当前区域所有规则 # 查看富规则 sudo firewall-cmd --list-rich-rules
3.4 使用iptables配置防火墙策略
如果你使用的发行版默认没有firewalld(如Debian、Ubuntu早期版本或某些精简服务器),iptables是直接的选择。
一个基础的、状态化(stateful)的iptables规则集示例,用于保护一台Web服务器(开放80、443,并管理SSH):
# 首先,设置默认策略:INPUT链默认丢弃,FORWARD链丢弃,OUTPUT链允许。 sudo iptables -P INPUT DROP sudo iptables -P FORWARD DROP sudo iptables -P OUTPUT ACCEPT # 允许本地回环(lo)接口的通信,这对许多本地服务至关重要。 sudo iptables -A INPUT -i lo -j ACCEPT # 允许已建立的连接和相关的连接(状态化防火墙的核心),确保对外发起的请求能有回应。 sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 允许ICMP协议(如ping),便于网络诊断,但生产环境可根据需要限制。 sudo iptables -A INPUT -p icmp -j ACCEPT # 开放SSH端口(假设为2222),并限制源IP。 sudo iptables -A INPUT -p tcp --dport 2222 -s 203.0.113.10 -j ACCEPT # 如果需要允许一个IP段,可以使用 -s 203.0.113.0/24 # 开放Web服务端口。 sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 最后,记录所有被丢弃的包(可选,用于调试,注意日志量可能很大)。 sudo iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: "保存iptables规则(否则重启后丢失):在CentOS/RHEL 7+上,可以使用iptables-save和iptables-restore,或安装iptables-services包后用service iptables save。 在Debian/Ubuntu上,可以安装iptables-persistent包,它在安装时会保存当前规则,之后使用netfilter-persistent save来保存。
# 通用方法:手动保存和恢复 sudo iptables-save > /etc/iptables.rules # 在系统启动时恢复,可以将恢复命令添加到 /etc/rc.local 或创建 systemd 服务。4. 高级安全实践与故障排查
4.1 SSH加固进阶技巧
使用Fail2ban防御暴力破解:即使改了端口、用了密钥,SSH端口依然会收到扫描。Fail2ban可以监控日志,当发现多次失败登录尝试后,自动临时封禁源IP。
# 安装(以Ubuntu为例) sudo apt install fail2ban # 复制默认配置文件进行自定义 sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # 编辑 jail.local,找到 [sshd] 部分,确保 enabled = true,并可以调整 bantime, findtime, maxretry。 sudo systemctl enable --now fail2ban监听内网地址:如果服务器只需要被内网管理,可以在
sshd_config中绑定内网IP。ListenAddress 192.168.1.100 ListenAddress ::1 # IPv6 回环地址使用TCP Wrappers进行额外控制:虽然逐渐被淘汰,但在某些简单场景下,
/etc/hosts.allow和/etc/hosts.deny文件可以提供一层额外的访问控制。# /etc/hosts.allow sshd: 192.168.1.0/24, 203.0.113.10 # /etc/hosts.deny sshd: ALL
4.2 防火墙策略优化
区域划分:使用
firewalld时,根据网络接口所处的物理位置绑定不同的区域。例如,eth0连接公网,绑定到public区域,规则严格;eth1连接内部管理网络,绑定到internal区域,规则宽松。sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent sudo firewall-cmd --reload使用富规则(Rich Rules)实现复杂逻辑:
firewalld的富规则非常强大,可以实现限速、日志记录、端口转发等。# 限制SSH连接速率,防止暴力破解 sudo firewall-cmd --permanent --add-rich-rule='rule service name=ssh-custom limit value=2/m accept' # 记录并丢弃来自某个IP的所有流量 sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.20.30.40" log prefix="BlockedIP " level="info" drop'定期审计规则:使用
firewall-cmd --list-all --zone=public或iptables -L -n -v定期检查规则,移除不再需要的条目,确保策略最小化。
4.3 常见连接问题与排查指南
问题1:修改SSH端口后,无法连接。
- 检查顺序:
- 防火墙:这是最常见的原因。确保新端口(如2222)已在防火墙中正确开放,并且没有限制源IP(除非你确认你的IP在允许列表中)。使用
sudo firewall-cmd --list-all或sudo iptables -L -n仔细检查。 - SELinux:如果系统启用了SELinux(如CentOS),它可能会阻止非标准端口的SSH服务。临时解决:
sudo setsebool -P ssh_port_t 2222,或永久添加端口标签:sudo semanage port -a -t ssh_port_t -p tcp 2222。 - 服务监听:确认
sshd正在监听新端口:sudo ss -tlnp | grep :2222或sudo netstat -tlnp | grep :2222。 - 配置文件语法:检查
/etc/ssh/sshd_config是否有语法错误,特别是Port指令前不能有#注释,且重启了服务。
- 防火墙:这是最常见的原因。确保新端口(如2222)已在防火墙中正确开放,并且没有限制源IP(除非你确认你的IP在允许列表中)。使用
问题2:公钥认证配置正确,但仍要求输入密码。
- 排查步骤:
- 服务器端文件权限:这是99%的问题所在。确保服务器上对应用户家目录下的
.ssh文件夹权限为700,authorized_keys文件权限为600。错误的权限(如755或644)会导致SSH出于安全考虑拒绝使用密钥。chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys - 公钥内容:检查
authorized_keys文件中的公钥内容是否完整,没有多余空格或换行。最好用ssh-copy-id来避免格式问题。 - SSH配置:确认
/etc/ssh/sshd_config中PubkeyAuthentication yes已启用。 - 客户端私钥权限:客户端私钥文件(如
~/.ssh/id_ed25519)权限应设置为600。
- 服务器端文件权限:这是99%的问题所在。确保服务器上对应用户家目录下的
问题3:防火墙规则似乎不生效。
- 排查思路:
- 规则顺序:
iptables规则是按顺序匹配的。如果你先有一条ACCEPT all的规则,后面的DROP规则就无效了。使用iptables -L -n --line-numbers查看规则顺序。 - 默认策略:检查
INPUT链的默认策略是ACCEPT还是DROP。如果默认是ACCEPT,那么没有明确DROP的流量都会被放行。 - firewalld重载:修改
--permanent规则后,必须执行firewall-cmd --reload才能生效,仅--reload不会加载永久规则。 - 多个防火墙工具冲突:确保系统没有同时运行
iptables服务和firewalld服务,它们会互相冲突。通常只启用一个。
- 规则顺序:
问题4:连接速度慢,尤其是登录时卡顿。
- 可能原因与解决:
- DNS反向解析:
sshd默认会尝试解析客户端的IP地址到主机名,如果DNS服务器响应慢或不可达,就会造成延迟。在sshd_config中禁用:UseDNS no - GSSAPI认证:如果不需要Kerberos认证,可以禁用以加快登录速度:
GSSAPIAuthentication no
sshd服务。 - DNS反向解析:
配置Linux的网络安全,尤其是SSH和防火墙,是一个从“可用”到“可靠”再到“安全”的渐进过程。没有一劳永逸的银弹,关键在于理解每个配置项背后的安全含义,并根据自己的实际环境(是暴露在公网还是内网,管理员的网络环境是否固定)来制定策略。我的习惯是,任何新服务器上线,第一件事就是配置密钥登录、修改SSH端口、设置防火墙白名单,然后再做其他操作。这套组合拳打下来,能挡掉99%的自动化脚本和初级攻击者,为服务器提供一个坚实的安全基线。
