服务器安全铁三角:防火墙、SSH加固与系统日志监控实战
1. 为什么服务器安全问题总是绕不开防火墙、SSH和系统日志干了这么多年Linux运维我越来越觉得这三样东西就是个铁三角。防火墙负责门禁SSH负责钥匙系统日志负责监控摄像头。缺了任何一环服务器就处于裸奔状态。先说一个最典型的场景一台新上线的云服务器默认开启了SSH密码登录root账号可以直接连防火墙规则是放行所有。这种情况放在公网上运气好能撑一晚上运气不好几小时内就会被扫描爆破。我见识过太多刚入行的朋友把服务跑起来就以为万事大吉结果第二天登录一看/var/log/auth.log里全是密密麻麻的Failed password记录系统负载莫名飙高CPU被挖矿程序占满了。为什么会这样因为公网上的扫描器是7x24小时不间断工作的。它们扫描的目标不是特定某台机器而是所有暴露在公网上的IP。你的服务器只要有个公网IP就必然会被扫。所以防火墙、SSH加固、日志监控不是可选优化项而是上线前必须做的基础操作。这篇文章我会把这三个模块的底层逻辑、实操命令、排错思路全部过一遍。内容覆盖大家搜索最多的那些问题SSH免密登录怎么配、连接失败怎么排查、防火墙黑白名单怎么设、系统日志怎么查看和防止篡改。我会尽量用实际场景来讲而不是只扔出一堆参数让你背。2. 防火墙从iptables到firewalld你到底该用哪一层2.1 firewalld的zone模型究竟在解决什么问题很多初学者一上来就被iptables那长长的规则链吓住了。其实iptables本身不难难的是规则的组织方式。你想想一台服务器上可能同时跑着Web服务、数据库服务、SSH服务每个服务要放行的端口不同来源IP也可能不同。如果用iptables纯命令行一条条加规则一多很快就会乱成一团而且不知道某条规则是谁加的、为什么加。firewalld解决的就是这个规则组织问题。它引入了一个叫zone区域的概念你可以把它理解成不同的信任等级。public区域默认区域适用于公网环境。进入的流量需要显式放行。internal区域适用于内网环境默认信任程度更高。trusted区域所有流量放行只适用于完全可信的网段。block区域拒绝所有入站流量只允许已建立的连接。我一般在服务器上只使用public trusted两个区域就够了。公网接口挂public内部管理网段挂trusted。逻辑很清晰外部访问被严格限制内部运维可以自由进出。2.2 企业场景下最常用的防火墙配置我们假设一个实际场景服务器上有Nginx80/443、MySQL3306只允许内网访问、SSH2222端口只允许办公网IP访问。第一步先确认当前生效的区域firewall-cmd --get-default-zone firewall-cmd --get-active-zones默认都是public。那我们就直接在public上操作firewall-cmd --permanent --add-servicenginx firewall-cmd --permanent --add-port80/tcp firewall-cmd --permanent --add-port443/tcp端口和服务两种方式效果一样。--service是firewalld预定义的服务名底层也是映射到端口。我习惯直接用--add-port因为更直观不用去记服务名映射表。然后是SSH和MySQL的精细控制。SSH只允许办公网IP 203.0.113.10访问MySQL只允许内网网段192.168.1.0/24访问firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.10 port protocoltcp port2222 accept firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.1.0/24 port protocoltcp port3306 accept firewall-cmd --reloadrich-rule就是富规则支持按来源IP端口协议做精细放行。上面的命令执行完后SSH和MySQL默认就是拒绝状态只有指定来源能访问。这里有一个新手特别容易犯的错误--permanent参数加上后规则不会立即生效必须执行firewall-cmd --reload。我见过有人在生产环境上加了--permanent没reload然后发现服务还是访问不了折腾了半天。2.3 防火墙排错的关键套路服务器连不上了第一个怀疑的就是防火墙。但排查要有顺序不能瞎试。我自己的排查链路是这样的先确认服务进程是否在监听ss -tlnp | grep 80确认防火墙区域和规则firewall-cmd --list-all用firewall-cmd --query-port80/tcp检查端口是否放行试一下本地回环能不能访问curl 127.0.0.1如果本地能通、外部不通大概率是防火墙或安全组问题用tcpdump -i eth0 port 80抓包看请求有没有到达网卡这套流程走下来问题基本能定位到具体环节。还有一个小技巧遇到复杂网络问题时可以先临时加一条DROP日志规则观察一下firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.0/24 log prefixBLOCKED: levelinfo drop然后在journalctl -f里观察被丢弃的流量。这个做法在生产环境上很有用可以确认是不是防火墙误拦了业务流量。注意firewalld只是iptables准确说是nftables的一个前端管理工具。规则写在/etc/firewalld/目录下最终会翻译成内核netfilter规则。理解底层是netfilter对你排查问题会有帮助。2.4 硬件防火墙和软件防火墙的操作逻辑对比热搜词里有华为USG防火墙规则库更新不了、ensp防火墙配置web登录这些关键词说明很多人在学网络设备的防火墙配置。华为USG之类的硬件防火墙逻辑和Linux防火墙完全不同。硬件防火墙的核心是安全策略Security Policy当流量经过防火墙时先匹配源地址、目的地址、服务然后决定动作是放行还是拒绝。它更接近路由交换的思维模式——重点在接口区域trust/untrust/dmz和策略的互相匹配上。在eNSP模拟器里配USG6000V最常踩的坑是配了安全策略但没配接口的区域或者策略的方向搞反了。比如从trust区域访问untrust区域安全策略的源区域要选trust目的区域要选untrust。方向反了流量直接就被默认拒绝策略拦掉了。华为防火墙默认是没有匹配到策略就丢弃这一点和Linux firewalld的默认行为类似但显示方式不同。Linux用firewall-cmd --list-all能看到所有规则USG要用display firewall policy查看。如果规则库更新不了先检查设备能否访问外网再检查License是否过期这两点是更新失败的常见原因。3. SSH连接故障、免密登录和批量管理的完整方案3.1 SSH连接失败排查清单从网络层到应用层SSH连接失败是运维里最常遇到的问题没有之一。热搜词里ssh连接失败、ubuntu ssh无法连接、crt软件ssh登陆交换机提示密钥这些都是高频搜索。我自己的排查思路是从外到内、逐层定位的。首先确认网络通不通ping 目标IP telnet 目标IP 22 nc -zv 目标IP 22ping通不代表22端口通22端口通也不代表SSH服务正常。telnet和nc是确认端口是否可达的最快方式。端口不通下一步检查防火墙和安全组。注意云服务器要同时检查两点云控制台上的安全组规则 服务器内部的firewalld/iptables。有时候安全组放行了但服务器内部防火墙没放行照样连不上。端口通但连接卡住或者报错就看SSH服务端状态systemctl status sshd ss -tlnp | grep :22 journalctl -u sshd -n 50日志是最可靠的。journalctl -u sshd能看到服务端记录的每一次连接尝试和认证失败原因。有一个很多人不知道的细节Ubuntu和Debian上SSH服务名是ssh不是sshd。所以在Ubuntu上执行systemctl status sshd会报Unit sshd.service could not be found别慌换成systemctl status ssh就行。老运维也经常在这上面卡一下。还有提示密钥类问题。用Xshell、CRT连交换机或者Linux服务器时提示host key验证失败多半是服务器端的host key变了。比如重装了系统、恢复了快照、换了机器客户端的known_hosts里还保存着旧的host key一比对不一致就会报错。解决办法很简单删除~/.ssh/known_hosts里对应的旧条目或者直接删掉整个known_hosts文件让它重新记录。CRT里是工具 → 主机密钥管理找到旧的主机名删掉。使用VS Code Remote-SSH连接远程服务器时如果提示握手失败优先检查服务端的SSH版本。老版本OpenSSH和新版客户端可能存在算法不兼容常见的解法是在服务端/etc/ssh/sshd_config里打开KexAlgorithms相关配置或者直接升级OpenSSH版本。3.2 SSH密钥认证免密登录的完整配置免密登录几乎是每台服务器上线后都要做的操作。配置本身很简单但很多人理解得不透彻导致出了问题不知道从哪排查。生成密钥对ssh-keygen -t ed25519 -C work-2024-t ed25519指定密钥算法-C是注释标识。我强烈建议所有新环境都用ed25519它比rsa更安全、密钥更短、生成更快。除非你要连接的是一些老旧的网络设备部分只支持rsa才用-t rsa -b 4096。生成的密钥对在~/.ssh/目录下id_ed25519是私钥绝对不能泄露id_ed25519.pub是公钥可以放到任何你需要登录的服务器上。把公钥放到服务器上ssh-copy-id -i ~/.ssh/id_ed25519.pub 用户服务器IP这条命令会自动把公钥追加到服务器上~/.ssh/authorized_keys文件里。执行过程会要求输入一次密码之后就实现免密登录了。有的服务器没有ssh-copy-id命令比如CentOS最小化安装有时候不带那就手动操作cat ~/.ssh/id_ed25519.pub | ssh 用户服务器IP mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys注意每一步的文件权限~/.ssh目录必须是700authorized_keys文件必须是600。权限过宽会导致SSH拒绝使用这个文件这是最容易被忽略的坑。配置完免密登录后记得改SSH服务端配置做加固# /etc/ssh/sshd_config PermitRootLogin prohibit-password PasswordAuthentication no PubkeyAuthentication yes改完后systemctl restart sshd从此只能通过密钥登录密码登录被禁止。这个操作能把暴力破解的成功率直接降到零。3.3 SSH批量登录与多服务器管理热搜词里有ssh批量登录这个场景很实际。几十台服务器如果一台台手动输入密码效率太低。我一般用两种方案。方案一配置好密钥后写批量执行脚本#!/bin/bash for ip in $(cat server_list.txt); do ssh -o ConnectTimeout5 root$ip uptime df -h | head -20 done-o ConnectTimeout5防止某个IP不通时卡很久。每台服务器执行命令后返回结果适合简单的批量巡检。方案二使用ansible做批量管理ansible本质上也依赖SSH但它支持并行执行、结果汇总、幂等操作比for循环脚本高级很多ansible all -i inventory.ini -m shell -a uptimeansible的inventory文件里定义所有服务器的IP和连接信息[web_servers] 192.168.1.10 ansible_userroot 192.168.1.11 ansible_userroot [db_servers] 192.168.1.20 ansible_userroot第一次用ansible批量连接时会提示确认host key。批量环境下这个提示会卡住脚本可以在ansible配置里关闭host key检查# ansible.cfg [defaults] host_key_checking False注意关闭host_key_checking只适用于内部可信网络。在公网环境下我建议保留host key检查防止中间人攻击。3.4 SSH大量连接攻击的防御策略网络攻击 ssh大量连接怎么办也是热搜词这个问题确实越来越常见。攻击方式无非两种暴力破解密码、短时间内建立大量SSH连接拖垮服务。防御手段一fail2banfail2ban的原理是监控SSH日志发现某个IP多次认证失败后就往防火墙里添加一条拒绝规则。我常用的配置# /etc/fail2ban/jail.local [sshd] enabled true port ssh filter sshd logpath /var/log/auth.log maxretry 3 bantime 3600 findtime 600maxretry3表示10分钟内失败3次就封禁bantime3600封禁1小时。日志路径要注意CentOS/RHEL是/var/log/secureUbuntu/Debian是/var/log/auth.log配错了就检测不到攻击。防御手段二修改SSH端口禁用root密码登录把SSH端口从22改成一个不常用的高位端口比如2299# /etc/ssh/sshd_config Port 2299修改后扫描器扫22端口发现是空的就会跳过这台机器。这不是绝对安全但能挡住绝大部分无差别扫描。同时配合PermitRootLogin prohibit-password就算密码被猜出来也没用。防御手段三限制来源IP如果可以确定访问来源直接在防火墙里限制SSH的来源IP段是最干净的做法。只让办公网IP访问其他全部拒绝暴力破解就直接没有机会了。4. 系统日志journalctl、日志持久化与只追加保护4.1 journalctl命令的日常使用思路系统日志是排查问题的第一手证据。现在的CentOS 7/Ubuntu 16.04都用systemd日志由journald统一管理查看工具就是journalctl。最简单的用法是查看本次启动的日志journalctl -b-b表示本次启动。排查系统起不来的问题这是最常用的命令。查看某个服务的日志journalctl -u sshd journalctl -u nginx-u指定unit只看这个服务的输出干净利落。如果想看最近的日志并持续跟进journalctl -u nginx -f-f就是follow模式和tail -f一个效果。排查nginx配置改完后有没有生效开着这个窗口然后reload配置日志会实时打印。查看指定时间段的日志journalctl --since 2024-01-01 10:00:00 --until 2024-01-01 12:00:00这个在排查某时段服务突然异常的问题时非常有用直接把日志锁定在那个时间段。4.2 传统日志文件与journald的配合关系很多人会问/var/log/messages或/var/log/syslog和journalctl看到的日志是不是重复的答案是它们记录的来源相同但存储方式不同。journald把日志存在二进制文件里通常在/var/log/journal/而传统的syslogrsyslog服务把日志写成纯文本文件。很多服务比如crond、sudo会同时写两个地方。我个人的使用习惯是日常排查看journalctl因为它支持按服务过滤、按时间过滤效率高。归档和审计看传统文本日志因为/var/log/messages是单纯文本可以用grep/awk随便处理也方便备份。需要特别注意的是journald默认情况下日志是只存在内存里的重启后日志就丢了Debian/Ubuntu上默认会把journal持久化到磁盘但CentOS上默认不会。要想持久化执行mkdir -p /var/log/journal systemctl restart systemd-journald创建/var/log/journal目录后journald会自动把日志写到磁盘上。这个操作做完重启后也能看到之前的日志了。4.3 如何保证系统日志只能追加防篡改配置热搜词里有保证系统日志只能追加这其实是一个安全加固要求。场景通常是服务器被入侵后攻击者会清理日志抹掉痕迹。为了防止这种情况我们可以给日志文件设置只追加属性让任何人都无法修改或删除已有内容只能追加新内容。chattr命令就是干这个的chattr a /var/log/messages chattr a /var/log/auth.log chattr a /var/log/securea表示append-only设置后文件就只能追加写入了。攻击者即使拿到root权限执行rm或者echo覆盖内容也会被拒绝除非先执行chattr -a去掉这个属性。注意一个前提这个属性需要文件系统支持。ext4、xfs都支持但有些云盘的格式化方式可能不支持。可以用lsattr查看属性是否设置成功lsattr /var/log/messages ----a---------- /var/log/messages设置完a属性后rsyslog写入日志会不会受影响不会因为追加写入是允许的只是修改和删除被禁止了。这个操作对运行中的服务完全透明。更严格的安全做法是配置远程日志服务器。让所有服务器把日志通过rsyslog实时传输到一台单独的日志服务器上攻击者入侵了业务服务器也清理不掉日志服务器上的记录。配置很简单业务服务器上在/etc/rsyslog.conf里加一行*.* 192.168.1.100:514日志服务器上开启udp 514端口的接收# /etc/rsyslog.conf 取消下面行的注释 $ModLoad imudp $UDPServerRun 514这样日志就实现了双写——本地一份远程一份。本地被改了远程的原始记录还在。5. 三大模块联动实战日志发现攻击、防火墙阻断攻击5.1 从日志中发现SSH暴力破解的完整过程单独讲完防火墙、SSH、日志现在把它们串起来模拟一个实战场景。一天早上你登录服务器感觉系统响应有点慢。你想确认是不是被暴力破解了于是查看SSH日志grep Failed password /var/log/auth.log | awk {print $(NF-3)} | sort | uniq -c | sort -nr | head这条命令的作用是从认证日志里筛出所有密码认证失败的记录提取来源IP$(NF-3)取的是倒数第4个字段在auth.log的格式里就是IP地址统计每个IP失败次数并排序。结果可能会看到32891 203.0.113.55 21450 198.51.100.23 10023 203.0.113.88看到这种上万的失败次数说明至少有规模的扫描器盯上你了。如果你想看看这个IP都尝试了哪些用户名grep Failed password /var/log/auth.log | grep 203.0.113.55 | awk {print $9} | sort | uniq -c | sort -nr大概率会看到root、admin、test、ubuntu这些常见用户名都被试了个遍。5.2 通过防火墙实时封禁攻击IP确认了攻击来源下一步就是封禁。使用firewalld的有两种方式。临时封禁重启后失效firewall-cmd --add-rich-rulerule familyipv4 source address203.0.113.55 drop永久封禁firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.55 drop firewall-cmd --reload如果你使用的是iptables命令行直接管理也可以用iptables -I INPUT -s 203.0.113.55 -j DROP-I表示插入到规则链的最前面这样流量最先匹配这条规则立即丢弃。封禁后一定要验证一下在封禁IP的机器上试着SSH登录一下确认确实连不上了。我遇到过一次封禁规则写的顺序有问题防火墙规则链里后面的放行规则优先级更高结果白忙活半天。5.3 用fail2ban实现自动化封禁手动封禁只能解决已经发现的攻击者但攻击IP是不断变化的。更好的方案是用fail2ban自动监控日志达到阈值后自动封禁。fail2ban的工作流程是监控日志文件 → 匹配失败模式 → 计数 → 超过阈值 → 调用防火墙命令封禁IP → 到达解封时间后自动解除。上面3.4节已经给出了基本配置。这里补充一个细节fail2ban可以配置邮件告警被封禁的IP会发邮件通知你[sshd] enabled true port ssh action firewallcmd-rich-rules[actiontypeDROP] mail-whois[nameSSH, destadminexample.com]配置好后systemctl restart fail2ban。之后攻击者再来3次失败后就会被自动封禁1小时并且你会收到告警邮件。5.4 复盘整个防御链路把整个防御链路串起来看防火墙负责第一道防线——限制可访问的端口和来源IP。SSH加固负责第二道防线——即使密码被猜中无法通过密码登录仅密钥认证。系统日志负责全程监控——记录每一次访问尝试、每一次登录成功失败。fail2ban负责联动——从日志中提取攻击行为自动通知防火墙封禁。这就是这三样技术的真正意义。单独学任何一个都是了解命令把它们串起来才是部署了防御体系。6. 实操中踩过的坑和值得长期坚持的习惯踩坑经历是最有价值的部分我分享几个真实案例。坑一firewalld和iptables共存冲突有一次在一台CentOS 7服务器上配置规则我习惯性地执行iptables -I INPUT -p tcp --dport 8080 -j ACCEPT结果完全不生效。查了半天才发现这台服务器用的是firewalld我手动加的iptables规则和firewalld的规则是并列存在的但firewalld加载的规则在后把我手动加的规则覆盖了。从那以后我明确了系统跑的是firewalld就统一用firewalld命令别混用。坑二系统日志文件权限被改导致rsyslog启动失败一次我图省事直接chmod 777 /var/log/messages结果rsyslog服务直接拒绝写入。很多服务对日志文件的权限有严格要求乱改权限会导致服务写不了日志。改错权限比日志多一个少一个严重得多。坑三SSH配置改错了把自己锁在门外这个应该很多人经历过。修改sshd_config里有语法错误重启服务后SSH直接挂掉而你又是在远程操作那就只能去机房或者找云控制台的VNC通道了。我的建议是每次修改sshd_config之前先备份然后用以下命令校验配置语法sshd -tsshd -t只测试配置文件的语法而不启动服务有错误会直接报出来。这条命令用习惯了基本不会出现把自己锁在门外的情况。值得长期坚持的几个习惯每台服务器上线第一件事修改SSH端口、禁止root密码登录、配置密钥登录。每台服务器都配置日志持久化别让journald的日志只留在内存里。日志文件目录加上a属性防篡改。防火墙规则用--permanent加完就--reload保证规则和配置文件一致。系统里保留至少一个非root用户并且配置sudo权限。防止root密码丢失或者被改后没法操作。最后再分享一个排查问题时的个人心得很多时候系统出问题了第一反应是服务坏了还是配置错了这个判断决定了排查方向。合理的顺序是看进程是否存活 → 看端口是否监听 → 看本地能否访问 → 看防火墙是否放行 → 看日志报错。前面的步骤都正常再怀疑配置文件的问题。有了这个顺序大部分网络和服务问题都能在几分钟内定位到根因。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →