服务器安全审计:90%风险藏在日志盲区
|
去年六月,我蹲在IDC机房门口啃盒饭,盒盖掀开三分钟就结了层油膜,筷子尖挑着半截没嚼烂的青椒,盯着防火墙日志面板右下角那个“最后更新:2024-06-17 15:22:03”的小字发愣——它卡在那儿十七小时没动过。运维老张路过踢了我椅腿一下:“别盯了,Syslog那边漏包,不是你写的转发脚本的事。”我嗯了一声,结果他转身就把我的脚本从crontab里删了。现在想起来,删得真对。
文章配图,仅供参考 服务器安全审计:90%风险藏在日志盲区。这话说出来我自己先笑了三秒——不是质疑数字,是笑这数字居然没人打脸。为什么站得住?优胜劣汰。活下来的系统,都是把告警当闹铃、把auditd当摆设、把/var/log/messages翻成《新华字典》厚度之后,还敢把faillog清空的主。清空不是为了掩盖,是硬盘快满了,而devops说“等Q3上ELK”。Q3早过了,ELK没上,/var/log/journal占了三百七十二G,但没人敢rm -rf——上次删journalctl历史,数据库连不上,DBA甩过来一个抓包截图,IP头都没校验完。 我原以为盲区在权限控制链里,比如sudoers配错了NOPASSWD,再比如某个定时任务偷偷用root跑curl。结果审计报告第一页写着:“未发现高危权限滥用”。但第七页附件二第三行夹着一行被折叠的日志:`systemd[1]: Started Run script /opt/bin/sync_cron.sh.` ——这个script我查过三次路径,/opt/bin下面压根没有sync_cron.sh。问运维,他回微信说“哦那个啊,早就改成软链到/tmp/.cron_xxx了,你们审计工具不扫tmp吧?”我截图发过去,他六十秒语音回我:“哎呀你点开看啊,ln -l里面写的是‘-> /dev/shm/run_sync’……”后面四十秒全是空调外机轰鸣声。 显示器右下角校样框还开着,是上次内网复盘通报PDF的PDF/X-1a预检弹窗,提示“嵌入字体缺失:Source Han Sans CN Light”。我关了三次,又弹三次。审稿间的灯是声控的,每次我说“这个字段必须加index”,它就灭掉,我得拍桌才能亮起来。第三次拍完,领导发来新消息:“刚才那条sudo日志,能不能确认是不是跳板机上的?不是我们主业务线的就行。”我没回。不是不想回,是正扒着rsyslog.conf里的$AllowedSender段落——它写了192.168.100.0/24,但实际进来的IP里有192.168.101.37。这IP谁配的?不知道。问网络组同事,他边调Wireshark过滤边摇头:“应该是上周那个变更工单里填错了,但我记得工单里写的是100网段啊……”他停顿五秒,点了保存,没存,点了另存为,文件名敲到一半,鼠标移开去接印刷对接的电话:“喂王工,样书第十八页那个二维码能换吗?扫出来跳钉钉群,但群满员了……” 所以你看,盲区根本不在“没记录”,而在“记了但不连贯”。fail2ban拦住了四千二百次SSH爆破,但它的日志只存在内存buffer里,每二十分钟flush一次,中间断电三次——最后一次,UPS延时十八秒,buffer里两百多条拦截全丢了。而监控平台报的“无异常登录失败”,依据是auth.log的tail -n 1000,因为agent配置文件里写了maxlines=1000。这个我敢打包票,打开/etc/fail2ban/jail.local第十七行,注释写着“# DO NOT CHANGE maxlines: breaks alerting chain in legacy infra”。legacy infra是他们叫法,我们叫“祖传yaml”。祖传yaml里有一行`ignoreip: 127.0.0.1/32 ::1/128 192.168.0.0/16`,但实际所有办公网出口做了NAT,真实源IP早被翻译成10.200.x.x——这个网段呢?不在ignoreip里,也没人往里加。所以每天凌晨三点,HR系统批量导出数据触发的三百多次连接,全被fail2ban当暴力扫描干掉了,顺带把HR服务器的SSH端口锁死四分半钟。 上个月跟安全部的人吵架,他指着Splunk里一条“低危”告警:“你看,这台主机连续七天有非标准用户执行sh”,我说:“那是运维写的部署脚本,名字叫do_deploy_sh.sh”,他顿了顿:“脚本名合规吗?”我说:“脚本名?脚本名是git commit message自动生成的,commit message里写的是‘fix: add sleep to avoid race’,生成规则是取冒号前两个词拼一起。”他摇头,说工具不能识别这种语义。我当时没接话。其实我想说,我们用的logrotate每天零点切日志,但配置里写了`dateext`和`dateformat -%Y%m%d-%H`,结果每天只切一次,-H部分永远是00,因为`dateext`和`hourly`不兼容——这个bug我在上线前三天就发现了,改配置时手抖按了ESC退出vi,没写`:wq`。现在/var/log/nginx/access.log.20240615-00里混着17:43到23:59的访问,但00:00之后的又跑去了access.log。Splunk按小时切片,它怎么认?认不出。它只认文件名后缀。 凉掉的外卖还在桌上,塑料盖子掀开后塌下去了一角,像一张微张的嘴。我其实不饿,就是忘了扔。领导下午三点发来的新指示说:“下次审计前,先把各节点的journalctl --disk-usage发个汇总。”我点了发送,附言里打了三个句号,没发出去。删掉重写,又打三个句号,还是没发。干脆关了企业微信。后台看到的数据和第三方工具说的数据从来就不一样——比如zabbix报某台Redis内存使用率82%,但redis-cli info | grep mem_human显示used_memory_human:1.83G,机器总内存2G。差的那0.3G,是jemalloc的碎片。zabbix不采集jemalloc_stat。这个我说不准,但DBA说“别信zabbix,要看info memory detail”。可detail里没写哪块内存归哪个key管。 反正是没法靠日志兜底了。我现在改用tcpdump抓关键时段的包,抓完丢给脚本筛出所有含“/api/v2/auth”的POST请求,再比对nginx access log里对应时间戳的行——但access log里的时间戳是$upstream_response_time,不是$request_time。所以经常筛出来一堆“超时但其实成功”的请求。有一次筛出四百一十九个疑似越权调用,实际全是前端重试机制导致的。我把这些原始pcap和筛选脚本打了个zip,邮件标题写了“【勿回】请确认是否需加固API入口”,附件名是20240621_api_auth_check_v2.zip。发出去两分钟后,邮件退回来了,提示“附件大小超出限制”。我重命名成v2-1.zip,再发,又退。第三次发的时候,把zip里两个无关的readme.md删了,终于发过去了。但直到今天,没人下载,也没人问。 下一步?我打算下周抽一天,把所有机器上的rsyslog、journald、auditd三个服务的logrotate配置全拉一遍,手动diff。不为了发现问题,是为了确认——到底哪些地方,是我们心照不宣、闭着眼跳过去的坑。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

