1. 项目概述:为什么你的服务器总在“裸奔”?
最近帮几个朋友处理服务器被黑的问题,发现一个通病:很多人把云服务器买回来,装好应用就跑,安全配置几乎为零。结果就是,服务器成了“肉鸡”,要么被拿来挖矿,要么成了DDoS攻击的跳板,数据泄露更是家常便饭。这让我想起一个比喻:你花大价钱买了栋别墅(云服务器),却把大门钥匙(root密码)藏在门口的地毯下,窗户(端口)全开着,这能不招贼吗?
今天要聊的“服务器安全加固”,就是给这栋别墅装上最基础的防盗门、防盗窗和监控系统。它不是一劳永逸的银弹,而是每个服务器管理员必须做好的“最低限度安全基线”。核心就三件事:用防火墙管好“门和窗”(网络访问)、用SSH密钥替换掉脆弱的“门锁”(密码登录)、定期用“探测器”检查墙体裂缝(漏洞扫描)。无论你是运维工程师、个人开发者,还是刚接触Linux的小白,这套组合拳都能让你的服务器从“裸奔”状态提升到“基本安全”的水平,抵御互联网上99%的自动化扫描和低水平攻击。
2. 安全加固的整体思路与方案选型
在动手之前,我们先理清思路。安全加固不是东一榔头西一棒子,而是一个有逻辑的、层层递进的过程。我的思路遵循“最小权限原则”和“纵深防御”理念。
2.1 防御层次设计
想象一下城堡的防御:最外层是护城河和城墙(防火墙),城门有特殊的令牌机制(SSH密钥),城内还有巡逻队定期检查(漏洞扫描)。对应到服务器:
- 网络层控制(防火墙):这是第一道防线。目标是只开放必要的端口(如80/443给Web,22给SSH管理),屏蔽所有其他无关的访问请求。相当于告诉外界:“除了正门和几个指定的送货口,其他墙上的洞都封死了,别来试探。”
- 访问层加固(SSH):这是管理通道的安全。默认的密码登录如同使用一把简单钥匙,容易被暴力破解。我们要换成更复杂的“指纹锁+动态令牌”机制(密钥对+禁用密码),确保只有你手里的“私钥”这把唯一钥匙能开门。
- 应用层检测(漏洞扫描):前两者是预防,这个是检测和补救。系统软件、运行的服务(如Nginx, MySQL)可能存在未知漏洞。需要定期主动扫描,发现潜在风险并及时修补,相当于定期检查城堡墙体是否有裂缝或白蚁。
2.2 工具选型与考量
为什么是iptables/firewalld、OpenSSH和Nessus/OpenVAS这个组合?
- 防火墙:对于现代Linux,
firewalld(CentOS/RHEL/Fedora)和ufw(Ubuntu/Debian)是更人性化的前端工具,它们底层依然调用iptables或nftables。我推荐新手从ufw或firewalld入手,因为它们命令简单,逻辑清晰。但对于追求极致控制和清晰规则的老手,直接配置iptables更能理解其包过滤的本质。本文会以更通用和基础的iptables为例进行原理讲解,并附带ufw的快速操作。 - SSH服务:
OpenSSH是事实标准,无需选型。关键在于如何正确配置其服务端(sshd)和生成客户端密钥。 - 漏洞扫描:商业工具中,Nessus非常强大,但家庭版免费有扫描IP数量限制。开源首选是OpenVAS(Nessus 早期的开源分支),功能全面,社区活跃。对于轻量级或快速检查,
lynis这种系统审计工具或nmap的脚本扫描也能起到一定作用。考虑到普适性和功能性,我们将重点介绍 OpenVAS 的部署和使用。
注意:所有操作都具有风险,尤其是防火墙配置错误可能导致你自己都无法连接服务器。务必在操作前,确保你有一个不受防火墙影响的备用连接方式(如云服务商的VNC控制台),并且在一个可承受风险的测试环境中先行演练。
3. 第一道防线:防火墙配置实战与原理
防火墙是你的网络哨兵。我们以经典的iptables为例,理解其工作流程,再给出快捷操作命令。
3.1 iptables 核心概念与链式逻辑
不要把iptables想得太复杂。你可以把它理解为一个有多层关卡(链)的检查站,每个数据包都要经过这些关卡的审批。
- 链(Chains):预设的检查点,主要有:
- INPUT:处理发往本机的数据包。比如有人访问你的服务器IP,包就进入INPUT链。这是我们防护的重点。
- FORWARD:处理经过本机转发的数据包(如果你的服务器是网关/路由器才用)。
- OUTPUT:处理从本机发出的数据包。
- 规则(Rules):每个链上的一系列判断语句。规则按顺序从上到下匹配。一个典型的规则包括:匹配条件(如端口22、协议TCP) + 动作(如ACCEPT接受、DROP丢弃、REJECT拒绝)。
- 表(Tables):规则的分类集合。最常用的是
filter表(负责过滤),还有nat表(负责网络地址转换)。
工作流程简化版:一个外部访问你服务器22端口的数据包,先进入INPUT链,从上到下匹配规则。如果第一条规则是“允许TCP 22端口”,它就被ACCEPT,送达SSH服务。如果匹配到一条DROP规则,它就被无声丢弃。如果所有规则都不匹配,则执行该链的默认策略(Policy)。
3.2 实战配置:从零构建安全规则集
假设我们是一台干净的服务器,需要开放SSH(22)、HTTP(80)、HTTPS(443),其他所有入站连接一律禁止。
# 1. 设置默认策略:最严格的策略是默认丢弃(DROP),然后显式允许需要的。 # 警告:执行前请确保已通过云控制台或已有会话连接,否则会立刻断线! iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # 出站通常宽松,也可设为ACCEPT # 2. 允许本地回环接口(lo)的通信,许多本地服务需要它。 iptables -A INPUT -i lo -j ACCEPT # 3. 允许已建立的连接和相关连接的数据包进入。这是关键,否则你的SSH现有连接也会断。 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 4. 开放SSH端口(22)。强烈建议后续改为非标准端口,这里先按标准来。 iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 5. 开放Web服务端口。 iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 6. 允许ICMP(ping),便于网络诊断,可选。如果担心被用于探测,可以禁止。 iptables -A INPUT -p icmp -j ACCEPT # 7. 查看当前规则 iptables -L -n -v执行后效果:现在,你的服务器只响应22、80、443端口的TCP新连接,以及所有已建立连接的后续包。其他任何新的入站连接请求都会被默默丢弃。
3.3 使用UFW快速配置(Ubuntu/Debian推荐)
如果你觉得iptables命令繁琐,ufw是绝佳选择。
# 1. 启用UFW sudo ufw enable # 同样,请先确保有其他连接方式 # 2. 设置默认策略(拒绝所有入站,允许所有出站) sudo ufw default deny incoming sudo ufw default allow outgoing # 3. 放行端口(比iptables直观多了) sudo ufw allow 22/tcp comment 'SSH' sudo ufw allow 80/tcp comment 'HTTP' sudo ufw allow 443/tcp comment 'HTTPS' # 如果需要放行特定IP,可以这样:sudo ufw allow from 192.168.1.100 to any port 22 # 4. 查看状态 sudo ufw status verbose3.4 防火墙配置的注意事项与心得
- 顺序至关重要:
iptables规则是从上到下匹配的。一定要把ESTABLISHED,RELATED的规则放在开放具体端口之前,确保已有连接不受影响。 - 先放行,后阻断:在修改默认策略为
DROP前,务必先把必须的端口(特别是SSH)的ACCEPT规则加好。 - 保存规则:
iptables规则重启后会丢失。必须保存:- CentOS/RHEL:
service iptables save或iptables-save > /etc/sysconfig/iptables - Ubuntu/Debian: 安装
iptables-persistent包,运行netfilter-persistent save。 - UFW 的规则是自动保存的。
- CentOS/RHEL:
- 云服务器安全组:别忘了,在阿里云、腾讯云等平台上,除了系统防火墙,还有一层安全组(Security Group)。它是云平台层面的防火墙,作用在主机虚拟网卡之前。最佳实践是“双重防护”:在安全组只放行必要端口,在系统内部再用
iptables/ufw做一层精细控制。即使系统被攻破,攻击者也无法从内部随意开放端口到外网。
4. 第二道防线:SSH密钥登录详解与彻底禁用密码
SSH是管理服务器的生命线,也是攻击者的首要目标。密码登录,尤其是弱密码或默认密码,是服务器失守的最常见原因。
4.1 为什么密钥比密码安全得多?密码认证是“你知道什么”(something you know),可能被猜中、被撞库、被键盘记录。而密钥认证是“你拥有什么”(something you have)加上“你知道什么”(私钥的密码短语)。它采用非对称加密:
- 公钥:放在服务器上
~/.ssh/authorized_keys文件中,相当于一把公开的锁。 - 私钥:保存在你的本地电脑上,严格保密,相当于唯一能开那把锁的钥匙。 即使攻击者拿到了公钥,也无法反推出私钥。暴力破解一个2048位或4096位的RSA密钥,以现有计算能力需要数万年。
4.2 生成与部署SSH密钥对以下操作在你的本地电脑(比如你的Mac或Windows上的WSL/Git Bash)进行:
# 1. 生成密钥对,推荐使用更安全的 ed25519 算法,或传统的 rsa 4096位 ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519_myserver # 或者 ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f ~/.ssh/id_rsa_myserver # 系统会提示你输入一个“密码短语”(passphrase),强烈建议设置!这为私钥再加一层保护。这会在~/.ssh/目录下生成两个文件:id_ed25519_myserver(私钥)和id_ed25519_myserver.pub(公钥)。
2. 将公钥上传到服务器
# 方法一:使用 ssh-copy-id 工具(最简单) ssh-copy-id -i ~/.ssh/id_ed25519_myserver.pub username@your_server_ip # 方法二:手动复制(通用) # 先在本地查看公钥内容 cat ~/.ssh/id_ed25519_myserver.pub # 复制输出的一大串字符,然后登录服务器,执行: mkdir -p ~/.ssh echo “粘贴你的公钥内容” >> ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys4.3 测试密钥登录并配置客户端
# 指定私钥文件进行连接测试 ssh -i ~/.ssh/id_ed25519_myserver username@your_server_ip如果提示输入私钥的密码短语(如果有设置),输入后即可登录,说明密钥生效。
为了让每次连接更方便,可以在本地~/.ssh/config文件中配置:
Host myserver HostName your_server_ip User username IdentityFile ~/.ssh/id_ed25519_myserver # 可选:禁用密码认证,强制使用密钥 PasswordAuthentication no配置后,只需ssh myserver即可连接。
4.4 服务器端SSH加固配置密钥部署成功后,需要修改服务器SSH服务端配置,以彻底关闭密码登录并加强安全。 编辑/etc/ssh/sshd_config文件:
sudo vim /etc/ssh/sshd_config找到并修改以下关键参数:
# 禁用root用户直接登录(先用普通用户登录,再su或sudo) PermitRootLogin no # 禁用密码认证,强制使用密钥 PasswordAuthentication no ChallengeResponseAuthentication no # 只允许特定的用户登录(可选,增加一层限制) AllowUsers username # 使用更安全的密钥算法(根据你生成的密钥类型调整) PubkeyAuthentication yes # 修改SSH监听端口(可选,可减少自动化扫描骚扰) Port 2222 # 改为一个非标准端口,例如2222 # 注意:修改端口后,防火墙和安全组必须同步放行新端口!每次修改sshd_config后,必须重载服务:
sudo systemctl reload sshd # 或 sudo service sshd reload重要:在reload之前,务必打开另一个SSH连接窗口保持登录状态,测试新配置是否生效。如果新窗口无法连接,说明配置有误,可以用旧窗口回滚修改。这是防止把自己锁在门外的“救命窗口”。
4.5 SSH安全进阶技巧与踩坑记录
- 私钥管理:私钥就是命根子。不要通过网络传输私钥,不要放入网盘。建议使用
ssh-agent来管理私钥和密码短语,避免每次输入。 - Fail2ban:这是一个神器。它能监控SSH等服务的日志,如果发现某个IP多次密码尝试失败,就自动用防火墙封锁它一段时间,有效对抗暴力破解。即使你用了密钥,安装它也能防护其他服务。
sudo apt-get install fail2ban # Debian/Ubuntu sudo yum install fail2ban # CentOS/RHEL - 修改端口:将SSH端口从22改为一个高位端口(如 2222、3522),可以避开绝大部分针对22端口的自动化扫描脚本。但这只是“安全通过隐匿”,不能替代密钥认证。
- 最惨痛的坑:有一次我修改了
sshd_config中的AuthorizedKeysFile路径,但没注意权限设置,导致所有密钥登录失效。而密码登录早已禁用。结果就是彻底被锁在外面,最后只能通过云控制台挂载系统盘来修复。教训:任何涉及认证文件的修改,都要双重检查路径和权限(.ssh目录700,authorized_keys文件600),并且永远保留一个活动的测试会话。
5. 第三道防线:漏洞扫描实战(以OpenVAS为例)
防火墙和SSH加固是预防,漏洞扫描则是健康检查。没有绝对安全的系统,软件漏洞(CVE)每天都在公布。我们需要一个工具来定期、自动化地发现这些风险。
5.1 OpenVAS部署与初始化
OpenVAS功能强大,但部署稍显复杂。这里以在Ubuntu服务器上部署为例。
# 1. 添加OpenVAS仓库并安装 sudo add-apt-repository ppa:mrazavi/openvas sudo apt update sudo apt install openvas # 2. 运行安装脚本,下载漏洞数据库(NVTs),这个过程很耗时,可能需要1-2小时 sudo gvm-setup # 安装脚本最后会输出一个管理员密码,务必保存!类似: # User created with password ‘xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx’. # 3. 启动所有相关服务 sudo gvm-start # 4. 检查服务状态 sudo gvm-check-setup部署完成后,OpenVAS会提供一个Web管理界面,通常通过https://服务器IP:9392访问。使用安装时提供的用户名(默认admin)和生成的密码登录。
5.2 首次扫描配置与执行
- 创建目标:在Web界面中,“Configuration” -> “Targets”,创建一个新目标。输入你的服务器IP地址或域名。对于扫描自己,可以选择“仅扫描本地主机”的配置。
- 创建扫描任务:在“Scan” -> “Tasks”,创建新任务。
- 给它起个名字,如 “Full System Scan”。
- “Scan Target” 选择你刚创建的目标。
- “Scan Config” 选择扫描策略。对于全面扫描,可以选择“Full and fast”。对于更深入但更慢的扫描,可选 “Full and very deep”。
- 启动扫描:创建任务后,点击绿色的播放按钮开始扫描。扫描时间取决于目标大小和策略,从几分钟到几小时不等。
- 查看报告:扫描完成后,状态变为 “Done”。点击报告名称,即可查看详细结果。报告会按风险等级(Critical, High, Medium, Low)列出所有发现的漏洞。
5.3 解读扫描报告与漏洞修复
OpenVAS的报告可能看起来很吓人,尤其是第一次扫描时。关键在于理性分析:
- Critical/High:必须立即处理。通常是已知的、有公开利用代码的远程代码执行或权限提升漏洞。例如,一个过期的、存在严重漏洞的OpenSSL版本。
- Medium:需要计划内修复。可能是信息泄露、拒绝服务漏洞等。
- Low/Info:通常是安全建议或信息提示,如SSH服务版本号被探测到。可根据实际情况决定是否处理。
修复漏洞的一般步骤:
- 阅读漏洞详情:点击漏洞条目,查看其描述、CVE编号、影响和解决方案(Solution)。OpenVAS通常会给出升级到某个版本的建议。
- 系统更新:绝大多数漏洞的修复方法是更新软件包。
# Debian/Ubuntu sudo apt update && sudo apt upgrade # CentOS/RHEL sudo yum update - 针对性修复:对于无法通过简单更新解决的,可能需要手动配置。例如,报告提示“SSH Weak MAC Algorithms Enabled”,你需要回到
/etc/ssh/sshd_config,按照建议禁用不安全的算法,如:Ciphers aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com - 重新扫描验证:修复后,针对该漏洞或运行一次快速扫描,确认风险已消除。
5.4 漏洞扫描的注意事项与心得
- 内网扫描注意:OpenVAS的扫描流量可能被内部防火墙或主机防火墙拦截,导致扫描结果不全。确保扫描器主机到目标主机的网络连通性。
- 性能影响:全面扫描会消耗大量CPU、内存和网络带宽,避免在业务高峰期对生产服务器进行深度扫描。可以安排在维护窗口进行。
- 误报:任何扫描工具都存在误报。对于报告中的漏洞,尤其是中低危的,需要结合实际情况判断。例如,一个“Web Server 可探测的版本信息”漏洞,如果你认为公开版本号无风险,可以将其标记为“假阳性”。
- 定期化与自动化:安全不是一次性的。应该建立定期扫描机制(如每周一次快速扫描,每月一次全面扫描)。OpenVAS支持定时任务(Scheduled Tasks)和邮件报告发送。
- 轻量级替代方案:如果觉得OpenVAS太重,对于简单资产,可以用以下命令快速检查:
lynis audit system:优秀的系统安全审计工具。nmap -sV --script vuln <target_ip>:使用Nmap的漏洞脚本进行扫描。sudo apt-get install unattended-upgrades:配置自动安全更新,防患于未然。
6. 常见问题与排查技巧实录
即使按照指南操作,你也可能会遇到问题。这里记录了几个我踩过的坑和解决方案。
6.1 防火墙配置后无法连接SSH
- 症状:配置完
iptables或启用ufw后,SSH连接立刻断开,且无法重新连接。 - 排查:
- 检查规则顺序:是否在设置
INPUT DROP前,已经添加了ACCEPT22端口的规则?或者ESTABLISHED规则是否在DROP之前? - 检查云安全组:你是否只修改了系统防火墙,却忘了云平台安全组也需要放行SSH端口(特别是改了非22端口后)?
- 使用控制台:通过云服务商的VNC或串口控制台登录服务器,检查防火墙规则。
iptables -L -n -v查看规则列表。sudo ufw status verbose查看UFW状态。- 如果规则混乱,可以临时清空所有规则并设置默认允许,先恢复连接:
iptables -F && iptables -P INPUT ACCEPT。
- 检查规则顺序:是否在设置
- 预防:永远遵循“先加允许规则,后改默认策略”的顺序,并保留一个活动会话进行测试。
6.2 SSH密钥登录失败
- 症状:配置了密钥,但仍提示输入密码,或者直接报“Permission denied”。
- 排查(在服务器上检查):
- 权限问题(最常见):执行
ls -la ~/.ssh/。目录权限必须是700(drwx------),authorized_keys文件权限必须是600(-rw-------)。如果不是,用chmod修正。 - 文件所有者:确保
.ssh目录和authorized_keys文件的所有者是当前用户,而不是root。 - SELinux干扰(CentOS/RHEL):如果SELinux处于强制模式,可能会阻止SSH读取密钥。可以尝试临时禁用SELinux测试:
setenforce 0。如果问题解决,需要为SSH设置正确的SELinux上下文:restorecon -Rv ~/.ssh。 - sshd配置:确认
/etc/ssh/sshd_config中PubkeyAuthentication yes且PasswordAuthentication no(测试时可先设为yes)。检查AuthorizedKeysFile路径是否正确。 - 查看日志:
tail -f /var/log/auth.log(Debian/Ubuntu) 或tail -f /var/log/secure(CentOS/RHEL)。尝试连接时,日志会给出详细的失败原因。
- 权限问题(最常见):执行
6.3 OpenVAS扫描不到任何结果或服务无法启动
- 症状:扫描任务瞬间完成,报告为空;或者
gvm-start失败。 - 排查:
- 内存不足:OpenVAS对内存要求较高,至少需要4GB以上。如果内存不足,扫描器进程可能会崩溃。用
free -h检查。 - NVTs未成功更新:
gvm-setup下载漏洞数据库可能因网络问题失败。尝试手动更新:sudo gvm-feed-update。 - 目标不可达:检查扫描器是否能ping通目标主机。检查目标主机的防火墙是否阻止了扫描流量(OpenVAS使用大量端口进行扫描)。
- 服务未完全启动:
sudo gvm-check-setup会检查所有服务状态。根据其输出修复问题。常见问题是PostgreSQL数据库或Redis服务未启动。
- 内存不足:OpenVAS对内存要求较高,至少需要4GB以上。如果内存不足,扫描器进程可能会崩溃。用
- 心得:对于生产环境,建议在一台独立的、性能较好的机器上部署OpenVAS,而不是在需要被扫描的业务服务器上。这被称为“单点扫描器”。
6.4 漏洞修复后服务异常
- 症状:按照扫描报告建议更新了软件包或修改了配置,导致某个服务(如Nginx, MySQL)无法启动。
- 排查:
- 查看服务日志:
sudo journalctl -u nginx --since today或sudo tail -f /var/log/mysql/error.log。 - 检查配置文件语法:更新后,旧的配置文件可能与新版本不兼容。例如,
nginx -t测试Nginx配置,mysqld --verbose --help检查MySQL参数。 - 回滚:如果更新了软件包,可以尝试降级到上一个版本。如果是配置问题,用备份的配置文件覆盖回来。
- 查看服务日志:
- 黄金法则:永远在修改生产环境前,在测试环境验证。对于关键配置文件的修改,先使用
cp config.conf config.conf.bak进行备份。对于系统更新,如果有重要业务,先在维护窗口进行,并做好回滚预案。
服务器安全是一个持续的过程,而不是一个项目。防火墙、SSH密钥和漏洞扫描这三板斧,构成了安全的基石。但别忘了,及时更新系统(yum update/apt upgrade)、使用强密码(对于必须用密码的地方)、最小化安装软件、定期审查日志(/var/log/)同样重要。我的习惯是,每部署一台新服务器,第一件事就是执行本文的这三步加固,这已经成了肌肉记忆。安全没有终点,保持警惕,定期检查,让你的服务器在互联网的汪洋大海中,成为一座坚固的堡垒。