资讯动态

服务器安全实战:攻击面盘点、日志审计与入侵排查

发布时间:2026/10/1 9:21:10 来源:尧图企业网站定制
凌晨三点被电话叫醒对方第一句话是服务器上多了个我不认识的账号——这种场景我经历过不止一次。每一次事后回看问题都不在于攻击手法有多高明而在于我们自己的防线本来就是筛子数据库端口对着整个内网敞开、运维账号密码三台机器共用、日志只写在本机磁盘上、备份跑了一年从没验证过。这篇东西不打算讲任何大道理就是把我这几年在几十台机器、几个集群上反复折腾出来的一套做法摊开怎么把系统的防线做到看得见、管得住、查得到。围绕的是服务器安全、攻击面盘点、日志审计、入侵痕迹排查、备份恢复这几件事做运维的、写后端的、刚转安全方向的同学都能直接拿去用不需要多深的前置基础。1. 把防线这两个字拆开攻击面盘点到底该盘什么很多人一说到安全加固第一反应是装个扫描器跑一遍然后照着报告打补丁。这个顺序是反的。扫描器只能告诉你你已知的东西有什么问题它没法告诉你你根本不知道自己还有哪些东西暴露在外面。真正该做的第一件事是把资产和暴露面盘清楚盘到你自己看了都吓一跳的那种清楚。1.1 为什么大多数团队的第一份资产清单都是错的我见过最典型的一份清单是这样来的负责人把 CMDB 里的机器列表导出来按业务分了组写了个 PPT然后就没有然后了。问题在于CMDB 里的东西和真实在跑的东西中间至少隔着三层失真。第一层是生命周期失真。测试环境开出来的机器没人回收业务下线了容器还在跑临时扩容的节点忘了登记。第二层是端口失真。装机的时候为了图方便把数据库、缓存、消息队列的监听地址写成了0.0.0.0想着内网嘛无所谓结果内网里任何一个被拿下的低权限机器都能直达。第三层是账号失真。离职同事的账号没停、外包临时开的账号没删、为了排查问题临时加的免密登录没撤。这三层失真叠在一起你面对的真实攻击面可能是清单上的三到五倍。所以盘点的目标不是写一份好看的文档而是找出所有能被外部触达的东西。1.2 三个维度拆资产网络暴露面、账号面、数据面我自己习惯把盘点拆成三个维度来做每个维度用不同的方法验证互相交叉。这样做的原因是单看任何一个维度都能自欺欺人三个维度对不上号的地方往往就是问题所在。维度盘点内容验证方法常见坑网络暴露面监听端口、对外域名、反向代理规则、安全组/防火墙放行在机器上实际抓监听在边界外做端口探测只信配置不信实际代理后面的服务被遗忘账号面系统账号、应用账号、数据库账号、密钥对、API Token导出账号列表对照人员名单检查密钥指纹共享账号、长期不过期的 Token、遗留的公钥数据面数据库、对象存储、备份文件、日志归档检查访问策略、检查加密状态、检查下载路径对象存储桶权限开放、备份文件放在可访问的 Web 目录下这张表看起来简单真正做起来最耗时间的是第二列的验证方法。因为验证必须动手不能靠问。你问开发这个端口对外开吗得到的答案十有八九是应该不开吧。1.3 用几条命令先把意外暴露揪出来别急着上商业工具先在最基础的层面确认一件事这台机器到底在监听什么。这几条命令我基本每次上机器都会跑一遍一分钟不到能过滤掉大部分低级问题。# 看所有 TCP/UDP 监听及其归属进程 ss -tulnp # 如果机器上没有 ss用老命令 netstat -tulnp # 看监听在 0.0.0.0 的也就是所有网卡都能进来的 ss -tulnp | grep 0.0.0.0 # 看已经建立的连接判断有没有异常的对外连接 ss -tnp state established第一条命令的输出重点看两列Local Address:Port和Process。凡是0.0.0.0:3306、0.0.0.0:6379、0.0.0.0:9200这类都要问一句这个真的需要全网卡监听吗。绝大多数场景下数据库和缓存的正确写法是监听在127.0.0.1或者明确的业务网段而不是所有网卡。第四条命令特别值得养成习惯。入侵者拿到 shell 之后要做的事情无非几件下载工具、回连控制端、横向移动、往外传数据这四件事里至少三件会产生对外连接。所以我平时巡机器的时候会顺手看一眼 established 的连接里有没有陌生的外部 IP 和不常见的高位端口组合。这个习惯帮我提前发现过两次异常都没等到告警触发。注意这些命令需要 root 或者具备相应权限才能看到进程归属。如果你在容器里跑看到的可能是宿主机的命名空间视角别被误导最好在宿主机上确认一遍。2. 收口的第一刀网络层与边界上的几个硬动作暴露面盘清楚之后接下来是收口。收口这件事最容易犯的错是哪出问题堵哪也就是黑名单思路。黑名单的问题是你永远只能堵住你已经想到的那些口子而攻击面是动态的。2.1 白名单思路为什么是唯一解白名单和黑名单的区别本质上是默认允许和默认拒绝的区别。默认允许的意思是只要我没明确禁止的就都能进来默认拒绝的意思是只要我没明确允许的一律进不来。这两种思路在运维成本上看起来差别很大黑名单几乎不需要维护白名单意味着每次有新需求都要改配置、走流程。但你要算的是另一笔账——一次被入侵的处置成本等于几百次配置变更的时间。所以我现在的原则很硬生产环境的入方向默认全拒按需逐条放行放行条目必须写清楚用途、申请人和有效期。具体落到操作上路由层的规则要尽量收敛到源地址 目的地址 目的端口三个要素齐全尽量避免0.0.0.0/0这种放行。如果业务上有面向公网的入口那入口应该只有一个也就是反向代理或者负载均衡那一层后面的应用机器一律不对公网暴露。2.2 管理入口的处理跳板、二次认证、来源限制管理入口是被盯得最紧的地方因为它直接通向最高权限。我处理管理入口通常分三步按重要性排序。第一步是收敛入口数量。一个团队如果有十个人每个人都能用自己的方式连生产机器那管理入口就有十种形态。正确的做法是只保留一到两个跳板入口所有运维操作必须经过跳板跳板本身不允许直接跑业务进程只做转发和审计。这样做的理由很直接审计点从 N 个变成 1 个你只需要保证一个地方做对了。第二步是加第二因素。单纯依赖密钥或者密码都会面临密钥泄露和密码撞库的风险。加一层基于时间的一次性口令或者基于硬件密钥的认证成本不高但能挡掉绝大部分凭据泄露导致的直接登录。第三步是来源限制。跳板机本身也不是谁都能连的应该限制在特定的办公网段或者办公网络出口。这一步经常被忽略理由是我们办公网 IP 不固定。这个问题的解法是收敛办公出口而不是放弃限制。2.3 加固清单与逐项验证方法只做配置不改完就撤是加固工作中最常见的半途而废。我习惯把加固项列成一张表每项都写清楚怎么改和怎么验证改了。下表是我自己用的版本你可以按需增删。加固项操作要点验证方法优先级禁止 root 直接登录修改 SSH 配置PermitRootLogin no用 root 直连应被拒绝用普通账号登录后sudo成功高禁用密码登录PasswordAuthentication no不带密钥连接应提示认证失败高限制可登录用户使用AllowUsers或AllowGroups未在名单内的账号连接被拒高缩短空闲超时ClientAliveIntervalClientAliveCountMax挂起会话后按预期时间断开中关闭不用的服务停用并禁用非必要 systemd 服务systemctl list-unit-files --stateenabled复查中内核参数收敛关闭不必要的转发与重定向用sysctl -a对照目标值中自动安全更新配置无人值守更新或定期窗口查看更新日志与实际补丁版本中改完之后验证这一步不能省。我遇到过改完配置忘了重启服务还以为已经生效的情况最后是因为一次演练才发现的。配置文件的修改不等于生效生效不等于被验证这两句话建议贴在工位上。3. 账号与权限绝大部分失守都发生在这里如果说网络层是第一道门那账号权限就是最后一道门而恰恰是这道门最容易被从里面打开。回顾我处理过的案例绝大多数都不是被什么精妙的漏洞打穿的而是凭据管理上出了问题。3.1 弱口令与口令复用的真实代价先说一个数据感受在任何一台对公网开放的机器上开 SSH日志里每天都会出现成百上千次来自各地的登录尝试用户名集中在root、admin、test、oracle、postgres这几个。这些尝试绝大多数会失败但只要有一个账号用了弱口令就足够了。口令复用是另一个更隐蔽的问题。开发同学为了方便把同一套口令用在本地开发机、测试环境、生产环境甚至用在某个第三方服务上。一旦那个防护最弱的第三方出问题泄漏出来的口令组合就会被拿去撞生产环境。这类攻击在日志里看起来非常像正常登录——来源 IP 陌生但用户名密码都对。应对办法没什么花活口令用密码管理器生成和保存长度足够每个系统不同能上密钥的地方一律上密钥密钥本身加口令保护。至于定期强制改密码这件事我的看法是如果配合了足够强度的随机密码和多因素认证强制轮换的收益其实有限反而会导致改一个字符这种敷衍行为。3.2 密钥登录的落地细节密钥登录不是把公钥扔进authorized_keys就完事了几个细节决定了它是真的更安全还是只是换了一种形式的风险。# 生成一对密钥推荐 ed25519比 RSA 更短更强 ssh-keygen -t ed25519 -a 100 -C opsexample -f ~/.ssh/id_ed25519_ops # -a 100 表示对私钥做 100 轮 KDF提高暴力破解私钥口令的成本 # -C 后面是注释写上用途和归属方便日后清理 # 检查已有公钥的指纹便于和人员名单对照 ssh-keygen -lf ~/.ssh/id_ed25519_ops.pub私钥一定要设口令这一点经常被跳过理由是每次连都要输太麻烦。解决办法是用 ssh-agent 缓存而不是取消私钥口令。另外authorized_keys里建议给每个 key 加上来源限制和用途注释from10.0.0.0/8 ssh-ed25519 AAAAC3... ops-2024-jumpfrom这一项能让密钥即使被复制走也只能从指定网段使用是一层成本极低但很有效的兜底。同时定期清理authorized_keys把离职人员和已经换掉的密钥删干净这件事最好写进季度检查清单。3.3 最小权限不是口号运维账号的粒度控制所有运维用同一个 root这种模式在小团队里太常见了。它的直接后果是审计失效——日志里所有高危操作都是 root 干的你无法区分是谁。间接后果是误操作风险极高一个人打错命令全组背锅。我的做法是每个人一个实名账号日常操作走实名账号需要高权限时通过 sudo 提权sudo 策略按命令粒度配置。# /etc/sudoers.d/deploy 示例 # deploy 组可以重启指定服务但不能执行任意命令 %deploy ALL(root) NOPASSWD: /bin/systemctl restart app.service, /bin/systemctl status app.service # 需要完整的 root 权限时必须走带审计的通道 %oncall ALL(root) /usr/bin/su -把sudo日志单独收集谁在什么时间提权、执行了什么命令一目了然。这套东西刚上线的时候会有人抱怨麻烦但只要在复盘会上把因为权限过大导致的误操作拿出来讲一次大家就理解了。提示给应用使用的账号权限要单独设计。应用账号不应该有交互式登录能力这一点可以通过把 shell 设为/sbin/nologin来实现同时限制它只能访问自己需要的数据目录。4. 让痕迹留下来日志、审计与告警的实操配置前面三节讲的都是不让进来这一节讲的是进来之后能被发现。这两件事的重要性是一样的因为没有任何防线是百分之百的被发现的时间差直接决定了损失大小。4.1 日志只放本机等于没放入侵者拿到权限之后标准的清理动作之一就是动日志删掉登录记录、清空命令历史、篡改审计文件。所以日志的第一原则是离开本机。只要日志在第一时间被送到了另一台机器上本机怎么删都影响不到你已经收到的副本。具体做法可以很朴素用系统自带的日志转发能力把auth、cron、sudo这几类日志实时推送到一台专门的日志服务器。这台日志服务器只收不跑业务防火墙里禁止它主动向外连接登录只允许从跳板机来。这样即使业务机器全被拿下你的日志链也是相对干净的。4.2 该重点关注的几类日志日志不是越多越好收集一堆没人看的日志等于没有。我按能不能直接反映入侵动作这个标准挑出下面几类重点看。日志类型位置/采集方式重点关注什么登录认证日志/var/log/auth.log或/var/log/secure成功登录的来源、失败次数、异常时间点提权与 sudo同上或独立 sudo 日志谁在什么时候提权、执行了什么计划任务/etc/cron.*、/var/spool/cron、systemd timer新增或修改的定时任务这是后门常用手法进程与启动项进程列表、systemd unit 文件异常路径的可执行文件、伪装成系统进程的名字网络连接连接列表、连接跟踪表高位端口的外连、陌生的外部地址Web 与应用日志应用自身输出大量异常请求、可疑参数、异常上传账号变更/etc/passwd、/etc/shadow的变更监控新增账号、UID 为 0 的账号、密码被改这张表里我认为最容易被忽略也最有价值的是计划任务和账号变更。原因很简单这两处是持久化控制的必经之路。想长期控制一台机器要么让程序开机自启要么留一个能随时登录的账号。把这两处的任何变更都纳入监控并告警能抓住相当一部分后续动作。4.3 三条低成本高收益的告警规则告警规则的常见问题是做太多导致天天响最后没人看。我建议从三条开始跑顺了再扩展。第一条非工作时段的管理员级登录。定义清楚你的工作时段和管理员级的范围比如能 sudo 的账号任何在工作时段之外的登录成功都推到值班群里。这条规则帮我抓到过两次正常时间之外的异常操作其中一次是外包人员在没有报备的情况下上线改配置。第二条短时间内大量登录失败后出现成功。这是典型的暴力尝试特征。检测逻辑很简单统计同一来源 IP 在窗口期内的失败次数超过阈值就关注一旦随后出现成功记录就立即告警。# 一个极简的检测思路示意 from collections import defaultdict import re FAIL_PATTERN re.compile(rFailed password .* from (\S)) OK_PATTERN re.compile(rAccepted .* from (\S)) def scan(lines, window100, threshold10): fails defaultdict(int) alerts [] for line in lines: m FAIL_PATTERN.search(line) if m: fails[m.group(1)] 1 m OK_PATTERN.search(line) if m and fails.get(m.group(1), 0) threshold: alerts.append(m.group(1)) return alerts这段代码只是讲清楚检测思路真实环境里不要自己造轮子解析日志用现成的日志分析组件更稳注意处理日志轮转和时区问题。第三条关键文件变更。/etc/passwd、/etc/shadow、/etc/sudoers、~/.ssh/authorized_keys以及 Web 根目录下的可执行文件任何变更都要告警。这条规则的价值在于它不依赖攻击者留下什么网络痕迹只要他动了文件就能发现。注意告警规则上线的前两周一定会吵这是正常的。要做的是逐条确认原因把正常业务产生的噪声用白名单消掉而不是把整条规则关掉。5. 一次异常登录的完整排查链路前面都是准备动作这一节讲真正出事的那个晚上。我把整个过程按时间顺序还原一遍包括我走了哪些弯路这样你遇到类似情况时能少绕几圈。5.1 起点一条凌晨的登录成功记录触发点是告警群里的一条消息某台应用服务器在凌晨两点十七分出现一次管理员账号的登录成功来源 IP 不在常用段内。当时的第一个念头是是不是有人加班但紧接着的第二个念头是加班也不会在这个时间点用这个账号。所以我按最坏情况处理先不动机器同时开始查。这里有个很重要的判断在确认之前不要做任何会改变现场的操作。重启、删文件、改密码这些动作都会破坏证据而且如果对方还在系统里你的动作也会被他看到。5.2 顺时间线走一遍从认证日志到进程树先看认证日志确认登录的事实和范围。# 看该账号最近的所有登录记录 grep deploy /var/log/auth.log | tail -100 # 看所有登录成功的记录时间、来源 grep -i Accepted /var/log/auth.log | tail -50 # 看登录历史包括来源 IP 和持续时间 last -ai | head -30 # 看失败记录判断之前是否有大量尝试 lastb | head -30这几条命令跑完基本能拼出时间线攻击者从哪个 IP 来、用什么方式密钥还是密码、尝试了多少次、什么时候成功。接着看进程和网络判断登录之后做了什么。# 按启动时间排序看进程重点看时间和登录时间接近的 ps -eo pid,ppid,user,lstart,etime,cmd --sortstart_time | tail -40 # 看所有对外连接 lsof -i -P -n | grep -v LISTEN # 看计划任务有没有被改过 ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ 2/dev/null crontab -l -u deploy 2/dev/null systemctl list-timers --all | head -20 # 看最近被修改过的文件 find /etc /usr/local/bin /home -type f -mtime -1 -ls 2/dev/null | head -40这几步里按时间排序看进程是最有效的一招。正常服务的启动时间是固定的或者有规律的凡是启动时间落在异常登录之后、路径又比较奇怪比如在/tmp、/dev/shm、/var/tmp下面的进程都值得重点看。同样find -mtime -1找出来的最近修改文件如果里面出现了不属于你的脚本那就是线索。5.3 确认影响范围怎么判断有没有留下后门确认了进来过之后第二个要回答的问题是还留着什么。这一步要看得更系统一点我通常按下面这张清单逐项确认。检查项命令/位置判断标准新增账号/etc/passwd、/etc/shadow变更时间出现不认识的账号尤其是 UID 为 0 的密钥后门~/.ssh/authorized_keys、/root/.ssh/出现不属于团队的密钥指纹计划任务cron 目录、systemd timer、at队列出现执行脚本、下载文件、回连的记录启动项systemd unit、rc.local、profile 脚本出现可疑的启动命令动态库劫持/etc/ld.so.preload这个文件通常不该存在有内容就要高度警惕服务伪装进程名与实际可执行文件路径不一致用/proc/pid/exe确认真实路径历史命令~/.bash_history、审计日志历史被清空本身就是信号这里特别提一下/proc/pid/exe。进程列表里显示的名字是可以伪造的攻击者可以把程序命名成rsyslogd之类的系统服务名来混过去。用ls -l /proc/pid/exe看它指向的真实文件路径就能戳破这层伪装。5.4 处置顺序隔离、取证、恢复该谁先谁后确认了范围之后才开始处置顺序很关键。我的顺序是先隔离网络再固定证据然后清理最后恢复业务。隔离的方式不一定是关机很多时候断掉入站和出站网络、保留机器运行状态更有利于后续分析。取证的部分至少要做到把关键日志和目标文件复制到一台独立的机器上记录下当前时间和机器状态保留内存里的信息如果条件允许。清理阶段不要想着手工删干净这类操作很难做到彻底稳妥的做法是基于干净的基础镜像重建把数据从备份里恢复然后逐个核对业务。最后一步很多人会跳过复盘的时候要改的是流程不只是修漏洞。同样是凭据泄露如果是流程问题比如密钥共享、离职未清理那么只改密码下周还会出事。6. 数据完整性与恢复假设已经失守来设计做安全设计的时候我习惯用一个假设当起点假设防线一定会被突破一次。在这个前提下再问自己最坏情况会损失什么。回答这个问题的过程中备份策略就自然成型了。6.1 备份的三个指标频率、隔离、可验证判断一个备份方案好不好我只看三个指标。频率决定了最多能丢多少数据。这个指标不是拍脑袋定的要按数据的产生速度和业务能接受的回退程度来算。有些日志类数据丢一小时问题不大交易类数据丢一分钟都是事故。隔离决定了备份在攻击中能不能活下来。备份如果和源数据在同一台机器、同一个网络、同一套凭据下面那攻击者往往能顺手一起处理掉。所以备份存储要在网络和凭据上和源系统解耦最好做到源系统只能写入备份不能删除备份。可验证决定了备份到底有没有用。备份文件损坏、备份任务静默失败、恢复脚本缺少依赖这些问题只有真的恢复一次才会暴露。所以我把恢复演练当成备份方案的一部分不是可选项。6.2 离线与不可变备份为什么必要在真实案例里我见过备份被一起加密的情况也见过备份服务器因为和被攻击的机器使用相同的凭据而沦陷。这两类问题靠备份更频繁是解决不了的必须靠备份本身的形态。我的建议是至少保留一层具备下面特征之一的备份离线平时不联网定期接入做一次同步、不可变写入后在保留期内无法删除或修改、或者只追加技术上只能新增不能覆盖和删除。这三者任选其一都能显著提高备份的存活概率。成本上离线介质和只追加策略其实都不贵贵的是没做之后的代价。6.3 恢复演练清单不做演练等于没有备份演练不需要很复杂找一台空闲机器按下面的清单走一遍把每一步的实际耗时和遇到的问题记下来这份记录比任何方案文档都有价值。演练步骤目的记录要点从零准备一台干净机器验证环境搭建时间和依赖清单实际耗时、遗漏的依赖拉取最近一次备份验证备份文件的完整性备份文件大小、校验值按文档执行恢复验证恢复文档是否可执行文档与实际不符的地方启动业务并做功能验证验证数据一致性关键业务路径是否正常记录数据时间点明确实际可恢复到的时间与预期目标的差距更新文档与脚本把发现的问题固化成改进责任人、完成时间这份清单我建议每个季度走一次至少每半年一次。练过两次以后团队对备份到底靠不靠谱这件事会有完全不同的底气。7. 把流程变成肌肉记忆演练与团队协作前面讲的都是技术动作但真正决定一个团队能不能扛住事故的是流程和人。技术动作再漂亮如果出问题的时候没人知道该谁上、该做什么一样会乱。7.1 一场不花钱的桌面演练怎么组织桌面演练的意思是不真动生产环境大家围着一张纸推演。听起来很虚但效果出乎意料地好因为它暴露的是沟通和决策层面的问题而这类问题平时根本看不见。我自己组织的流程通常是这样的先准备一个假设场景比如某台对外服务机器在凌晨出现异常登录可能已被植入持久化程序。然后把团队分成两三个角色组一组负责技术排查一组负责对外协调和记录我扮演提供增量信息的上帝视角每隔十分钟丢一条新信息进来比如现在发现另外两台机器也有相同来源的连接、备份服务器上出现了异常登录。整个过程两小时左右最后半小时做复盘。这个过程中最常暴露的三个问题是没人负责记录时间线、决策卡在等某个人的确认上、对外口径不统一。这三个问题在真实事故里都会放大越早发现越好。7.2 值班交接和临时沟通的一点经验事故处理期间的信息同步我的经验是尽量用同一个通道尽量用时间戳。不要在三个群里同时讨论不要用语音传结论凡是关键决策都落到文字上并且带上时间。原因很实在事后复盘要还原当时为什么这么决定如果只有口头记录这段永远说不清楚。值班交接要把三样东西传下去当前的状态是什么、已经做了什么、下一步计划是什么。这三样东西每次交接都写一遍看起来重复但它能避免以为对方知道这种最典型的协作失败。7.3 复盘怎么写才有价值复盘文档我见过很多种写得最有用的那种通常只有三部分时间线、根因、改进项。时间线要求精确到分钟写清楚每个时间点观察到什么、做了什么动作、结果如何。这一部分的价值在于它能让你看到发现问题和确认问题之间的时间差而这个差往往就是损失的主要来源。根因部分要往下追问几层。比如服务器被异常登录第一层原因是凭据泄露第二层原因可能是密钥在多个环境复用第三层原因是团队没有凭据管理工具。只写第一层改进措施就会变成换个密码下一周同样的事还会发生。改进项要具体到人和时间而且要控制数量。一次复盘列出几十条改进项最后一定一条都落不了地。我一般要求不超过五条每条都是明确的可验证动作。这套东西做下来最直接的感受是安全工作不是买几个产品就完事它更像是在日常运维的每个细节里持续做减法。我个人的一个习惯是每周花十分钟翻一遍登录失败次数最多的来源看看有没有新的异常模式另外给跳板机挂了一个简单的登录通知任何人登录都会在群里留一条记录成本几乎为零但心理上的约束作用非常明显。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑