前几篇都在说"怎么变快",这篇说"怎么别被人打"。顺手做了一次完整的安全体检,把能堵的都堵上了,中间还被宝塔坑了一把——那部分放在最后,因为它差点让我重演 8 月那次事故。
一、最严重的一个:8080 端口把防护全绕过去了
架构是这样的:nginx(443) → 127.0.0.1:8080 → 容器 Apache。问题在于 compose 里写的是 "8080:80",这个写法等于 把容器的 80 端口直接映射到了公网。
实测:
http://服务器IP:8080/xmlrpc.php
→ 405 "XML-RPC server accepts POST requests only."
也就是说,我在 nginx 里写的 location = /xmlrpc.php { deny all; } 完全没用——攻击者绕开 nginx 直接打容器就行了。同理,安全响应头、访问日志、限流,全部形同虚设。
修法一行:
- "8080:80" # 公网可达
+ "127.0.0.1:8080:80" # 只有宿主机能连
改完 docker compose up -d,外部直接 ECONNREFUSED。这种"以为有防护其实没有"的情况,比完全没防护还危险。
二、SSH 一直在被人尝试登录
翻了一下登录失败记录:
最近失败登录:447 次
chenhuil@115.29.185.119
pengfei@115.29.185.119
root@14.103.39.152
而且配置是 PermitRootLogin yes + PasswordAuthentication yes,服务器上也没装 fail2ban、防火墙是关的。等于全靠密码复杂度硬扛。
处理:
- 装 fail2ban,10 分钟内失败 4 次就封 1 天
- 生成密钥、验证能用之后,关掉密码登录(
PasswordAuthentication no+PermitRootLogin prohibit-password)
验证方式很朴素但有效:先在本机用密钥登录成功,再关密码,再登一次。失败就回滚。
三、其他几个小口子
| 问题 | 影响 | 处理 |
|---|---|---|
REST /wp/v2/users 可读 |
暴露管理员用户名 reimu0721user |
移除路由,返回 401 |
/?author=1 跳转 |
同样泄露用户名 | 重定向回首页 |
| XML-RPC 仍可从 PHP 层响应 | 暴力破解入口 | xmlrpc_enabled=false + 去掉 X-Pingback |
| 注册只靠蜜罐 | 批量注册 | 算术人机验证(HMAC 签名)+ 同 IP 每小时限 3 次 |
| 登录无频率限制 | 可被爆破 | 同 IP 15 分钟失败 5 次锁定 |
| 没有 CSP | XSS 少一层兜底 | 加 object-src 'none'; base-uri 'self'; frame-ancestors 'self' |
wp-config.php 权限 644 |
同组用户可读数据库密码 | 改 640 |
| 登录报错区分"用户不存在/密码错" | 辅助猜用户名 | 统一成"账号或密码不正确" |
| 宝塔面板 11451 对公网开放 | 面板被爆破 = 整机失守 | 设置随机安全入口 |
四、被宝塔坑的那一把
处理面板时执行了 bt restart。然后整站 403。
查下来是这样的:宝塔面板重启时会跑它的"安全任务",把 /www/server/panel/data 递归改成 chmod 600 + chown root。而我这套 Docker 部署的数据目录正好在这个路径下面:
/www/server/panel/data/compose/myblog/
├── wp_data ← WordPress 全站文件
└── db_data ← MySQL 数据目录
结果就是:目录失去 x 位、文件属主变成 root,Apache 读不了 → 全站 500;MySQL 的数据目录也一起被打成 drw------- root:root——它当时还能跑,是因为进程已经打开了文件句柄,但下一次重启必死。
这就是 8 月那次"挂六天"的同一个故障:目录权限被改成 600,MySQL 误判成空库,然后 abort。
在面板源码里找到了元凶(class/jobs.py:486),一行被注释掉的:
chmod -R 600 /www/server/panel/data;
chown -R root:root /www/server/panel/data;
恢复方法:wp_data 归 33:33、目录 755 文件 644;db_data 归 999:999、目录 755 文件 660。两个容器重启,mysqld is alive。
加了兜底
光修好不够,得防它再来一次。加了个**每 5 分钟**跑一次的守护脚本:
- 属主不对 →
chown -R回来 - 目录缺
x位 →chmod 755 - 站点返回非 200 → 自动重启容器并记日志
五、现在的体检结果
敏感文件 .git/.env/wp-config.php.bak/.sql → 全部 404
wp-config 直接访问返回空 body(PHP 已执行,无源码泄露)
目录列表 uploads / plugins 均不可列
用户枚举 401
XML-RPC 403 + 无响应头
安全头 CSP / HSTS / XFO / nosniff / Referrer / Permissions 齐全
X-Powered-By 已隐藏
TLS 1.3 + HTTP/2,证书剩 89 天
MySQL 3306 未对公网开放
SSH 仅密钥登录 + fail2ban
8080 已关闭
六、给同样跑宝塔 + Docker 的人
- compose 里的端口映射一定写
127.0.0.1:端口:端口,除非你确实要对外暴露。反代架构下写"8080:80"等于把所有 nginx 防护白给。 - 数据目录别放在
/www/server/panel/data下面。宝塔的安全任务会递归 chmod 这个目录,Docker 数据放里面就是待爆的地雷。 - 面板重启(
bt restart)这种操作,动手前最好确认一遍站点健康检查。 - 改 SSH 之前一定先用密钥验证能登,再关密码——不然就是把自己关在门外。
折腾完这一轮最大的感受是:安全这件事,出事之前全是"看起来没问题"。8080 那个端口,配了三个月,谁也没觉得有问题——直到有人真的去敲了一下。

Comments NOTHING