网站整改自查报告

 人参与 | 时间:2026-10-17 07:06:53

上周三凌晨两点,网站我被运维电话叫醒——首页轮播图挂了,整改自查点进去直接跳转到外部博彩页面。报告这不是网站第一次了。上个月后台日志里就出现过异常上传记录,整改自查当时以为是报告误报,没深究。网站现在回头看,整改自查那个被忽略的报告警告就是今天这场事故的伏笔。

我们团队六个人,网站负责一个日活三万左右的整改自查内容站。技术栈不复杂,报告Nginx + PHP + MySQL,网站前端用了点Vue。整改自查按理说不该出这种低级问题。报告但事实是,问题出了,而且不止一处。

一、上传接口的洞比想象中大

先说最要命的。文件上传模块用的是三年前写的代码,校验逻辑只有一句 if (in_array($ext, ['jpg','png','gif']))。MIME类型没查,文件头没验,路径参数直接拼进 move_uploaded_file。攻击者上传了一个 .jpg 后缀的PHP文件,配合Nginx一个配置疏漏——location ~ \.php$ 没限定目录——直接拿到了webshell。

我后来在服务器上翻到那个文件,藏在 /uploads/2024/03/ 下面,名字叫 thumb_1.jpg。用 cat 一看,开头是 GIF89a,后面跟着一句 eval($_POST['cmd'])。简单粗暴,但有效。

整改动作:上传目录禁止PHP解析,加 location ^~ /uploads/ { location ~ \.php$ { deny all; } }。文件校验改成三重——后缀白名单、MIME检测、getimagesize() 验证。上传后重命名,去掉原始文件名里的所有特殊字符。

二、后台入口藏了但没完全藏

后台路径改成了 /admin_2023/,以为够隐蔽。结果日志里每天都有几十次扫描 /admin、/wp-admin、/manage 的请求。更糟的是,后台登录没有验证码,没有失败锁定。我用Burp跑了一遍,密码 admin123 在第三十七次尝试时成功——测试账号忘了删。

这事怪我。去年做活动临时开的账号,活动结束只删了前端入口,数据库里的记录还在。密码是 admin123,用户名是 test。攻击者不需要爆破,直接撞库就行。

整改动作:后台加IP白名单,只允许公司出口IP访问。登录失败五次锁半小时,验证码换成滑动拼图。所有测试账号全部删除,数据库里扫了一遍 user 表,又揪出两个废弃账号。

三、SQL注入点藏在搜索参数里

搜索功能用的是 LIKE '%{ $keyword}%',没过滤。我试了 ' OR 1=1 --,页面返回了全部文章。再试 UNION SELECT,能读到 admin 表的 password 字段。虽然密码是bcrypt哈希,但拿到哈希就等于拿到了一半。

这个洞存在了至少八个月。日志里能看到有人用sqlmap扫过,只是没继续深入。可能是嫌数据量小,不值得。

整改动作:全部改PDO预处理。搜索关键词加长度限制,超过五十字符直接截断。数据库账号降权,只给 SELECT、INSERT、UPDATE,删掉了 DROP 和 FILE 权限。

四、日志和备份是最后一道防线

出事那天,我第一反应是查日志。结果发现Nginx的 access.log 只保留七天,PHP错误日志根本没开。备份倒是每天跑,但备份文件放在同一台服务器上,攻击者要是删库,备份也跟着没。

整改动作:日志保留三十天,异地同步到对象存储。备份改成每日全量+每小时增量,存到另一台独立服务器,脚本跑完发邮件通知。恢复流程写成了文档,每一步都有截图,新人照着做也能恢复。

写这份报告的时候,我又扫了一遍漏洞。还发现两个低危问题:Cookie没加 HttpOnly,phpinfo 测试文件忘了删。已经顺手处理了。

安全这事没有一劳永逸。今天补上的洞,明天可能因为新功能又开一个。我的做法是每周五下午花一小时看日志、跑扫描、检查更新。不复杂,但能挡住大部分脚本小子的自动扫描。

最后说一句:别信“我们的站太小,没人会攻击”这种话。攻击是自动化的,你的站再小,只要有一个洞,就会被扫到。区别只是早晚。

顶: 1438踩: 9