Typecho 安全加固完整指南
一、检查 Typecho 运行环境要求
bash
#部署环境:Rocky8 + Nginx/1.20 +MySQL8.0 +PHP8.4
#检查操作系统版本
[root@rocky8 ~]#cat /etc/redhat-release
Rocky Linux release 8.5 (Green Obsidian)
#检查Nginx版本
[root@rocky8 ~]#nginx -v
nginx version: nginx/1.20.1
#检查MySQL版本
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.28 |
+-----------+
1 row in set (0.00 sec)
#检查 PHP 版本(需 7.4 以上)
[root@rocky8 ~]#php -v
PHP 8.4.11 (cli) (built: Jul 18 2026 02:14:30) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.11, Copyright (c) Zend Technologies
with Zend OPcache v8.4.11, Copyright (c), by Zend Technologies
#检查数据库扩展(MySQL / PostgreSQL / SQLite)
[root@rocky8 ~]#php -m | grep -iE "pdo_mysql|pdo_pgsql|pdo_sqlite|mysqli|sqlite"
mysqli
pdo_mysql
pdo_pgsql
pdo_sqlite
sqlite3
#检查 CURL 扩展
[root@rocky8 ~]#php -m | grep -i curl
curl
#检查mbstring / iconv
[root@rocky8 ~]#php -m | grep -iE "mbstring|iconv"
iconv
mbstring
二、第一优先级:立即执行(高危漏洞)
2.1、删除安装文件(反序列化漏洞根源)
Typecho ≤ 1.2.0 存在 install.php 反序列化漏洞,可导致远程代码执行
bash
# 删除 install.php
[root@rocky8 ~]#rm -f /data/nginx/typecho/install.php
# 删除 install 目录
[root@rocky8 ~]#rm -rf /data/nginx/typecho/install/
# 确认删除
[root@rocky8 ~]#ls /data/nginx/typecho/ | grep -i install
2.2、检查 Typecho 版本
bash
#检查 Typecho 版本
[root@rocky8 ~]#grep "const VERSION" /data/nginx/typecho/var/Typecho/Common.php
public const VERSION = '1.3.0';
如果版本 ≤ 1.2.0,务必升级到 1.2.1+(修复了反序列化漏洞)
三、第二优先级:修改后台入口(防暴力破解)
3.1、修改 admin 文件夹名,防穷举
bash
# 改成别人猜不到的名字
[root@rocky8 ~]#mv /data/nginx/typecho/admin /data/nginx/typecho/pipixia2026
3.2、修改配置文件中的后台路径
bash
[root@rocky8 ~]#sed -i "s|define('__TYPECHO_ADMIN_DIR__', '/admin/');|define('__TYPECHO_ADMIN_DIR__', '/pipixia2026/');|" /data/nginx/typecho/config.inc.php
[root@rocky8 ~]#grep "__TYPECHO_ADMIN_DIR__" /data/nginx/typecho/config.inc.php
define('__TYPECHO_ADMIN_DIR__', '/pipixia2026/');
效果:原来的 /admin/ 无法访问,只能用 /pipixia2026/ 登录
四、第三优先级:Nginx 层面防护
4.1、屏蔽危险目录的 PHP 执行
bash
[root@rocky8 ~]#vim /apps/nginx/conf/conf.d/typecho.conf
#屏蔽 config.inc.php
location ~* config\.inc\.php$ {
deny all;
}
#屏蔽 .htaccess
location ~* \.htaccess$ {
deny all;
}
#屏蔽敏感文件
location ~* /\.(git|svn|bak|log|sql)$ {
deny all;
}
#屏蔽上传目录 PHP 执行
location ~* /usr/uploads/.*\.php$ {
deny all;
#屏蔽 usr/var 目录 PHP
location ~* ^/(usr|var)/.*\.php$ {
return 403;
}
#再次屏蔽(双重保险)
location ~*^/(config\.inc\.php|\.htaccess)$ {
return 403;
}
}
[root@rocky8 ~]#nginx -t
[root@rocky8 ~]#nginx -s reload
效果:即使黑客上传了 PHP 木马到 usr/var 目录,也无法执行
五、第四优先级:PHP 层面加固
5.1、禁用危险 PHP 函数,防代码执行
bash
# 找到 php.ini
[root@rocky8 ~]#find / -name "php.ini" 2>/dev/null
/etc/php.ini
[root@rocky8 ~]#vim /etc/php.ini
# 编辑 php.ini,找到 disable_functions,添加:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,assert,phpinfo,eval,pcntl_fork
禁用 PHP 中这些危险函数,防止黑客利用它们执行恶意命令!
#命令执行类(最危险)
→ 黑客利用这些可以直接在服务器上执行命令!是 Webshell 核心利用函数!
exec:执行外部命令,返回最后一行输出
system:执行外部命令,直接输出结果
passthru:执行外部命令,直接输出原始结果
shell_exec:执行命令,返回完整输出
popen:打开进程文件指针,可读写
proc_open:执行命令并控制输入/输出/错误
pcntl_exec:在当前进程空间执行程序
pcntl_fork:创建子进程(fork 炸弹)
#网络探测类
→ 黑客可以探测内网、下载恶意文件、SSRF攻击!
curl_exec:执行 cURL 请求
curl_multi_exec:批量执行 cURL 请求
#信息泄露类
→ 黑客可以读取配置文件、泄露服务器配置和源码,帮助攻击者精准定位漏洞!
phpinfo:输出 PHP 全部配置信息
show_source:高亮显示 PHP 源码
parse_ini_file:读取 ini 配置文件
#代码执行类
→ 攻击者可注入恶意代码字符串,直接控制服务器!
assert: 断言失败时可执行代码,被利用执行恶意代码
eval:将字符串作为 PHP 代码执行
5.2、限制文件上传大小,防 Webshell
bash
[root@rocky8 ~]#vim /etc/php.ini
# 同样在 php.ini 中
upload_max_filesize = 2M
post_max_size = 8M
[root@rocky8 ~]#sudo systemctl reload php-fpm.service
[root@rocky8 ~]#sudo systemctl restart php-fpm.service
六、第五优先级:服务器层面加固
6.1、开启 HTTPS(强烈建议)
bash
# 使用 certbot 免费证书
yum install -y certbot python3-certbot-nginx
certbot --nginx -d 8.138.236.75
或者在阿里云控制台申请免费 SSL 证书
6.2、修改 SSH 端口(防扫描)
bash
# 编辑 sshd 配置
sed -i 's/#Port 22/Port 52365/' /etc/ssh/sshd_config
# 重启 sshd
systemctl restart sshd
# 然后去阿里云安全组放行新端口 52365
6.3、开启 fail2ban(防暴力破解)
bash
#Fail2ban 防护 Typecho 后台,5次失败封1小时
[root@rocky8 ~]#dnf install -y fail2ban
[root@rocky8 ~]#systemctl enable fail2ban
[root@rocky8 ~]#systemctl start fail2ban
[root@rocky8 ~]#cat > /etc/fail2ban/filter.d/typecho.conf << 'EOF'
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*/(pipixia2026|admin)/login.*" (401|403|404)
ignoreregex =
EOF
[root@rocky8 ~]#cat > /etc/fail2ban/jail.d/typecho.conf << 'EOF'
[typecho]
enabled = true
port = http,https
filter = typecho
logpath = /data/nginx/typecho/access.log
maxretry = 5 #5次失败就触发封禁
findtime = 300
bantime = 3600 #封禁1小时
EOF
[root@rocky8 ~]#touch /data/nginx/typecho/access.log
[root@rocky8 ~]#chown nginx:nginx /data/nginx/typecho/access.log
[root@rocky8 ~]#chmod 644 /data/nginx/typecho/access.log
[root@rocky8 ~]#ls -lh /data/nginx/typecho/access.log
-rw-r--r-- 1 nginx nginx 0 Jul 23 11:24 /data/nginx/typecho/access.log
#后续 Nginx 访问日志会自动写入这个文件,不需要手动维护
# 检查Fail2ban 配置文件是否有语法错误
[root@rocky8 ~]#fail2ban-client -t
[root@rocky8 ~]#systemctl restart fail2ban.service
[root@rocky8 ~]#systemctl status fail2ban.service
# 查看 Fail2ban 状态确认防护生效
[root@rocky8 ~]#fail2ban-client status typecho
Status for the jail: typecho
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /data/nginx/typecho/access.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
#用 typecho 规则去扫描 access.log,看能匹配到几条
[root@rocky8 ~]#fail2ban-regex /data/nginx/typecho/access.log /etc/fail2ban/filter.d/typecho.conf
#后续运维
# 查看被封 IP 列表
fail2ban-client status typecho
# 解封 IP,如果有IP被封,再解封
fail2ban-client set typecho unbanip <真实被封的IP>
# 查看访问日志
tail -f /data/nginx/typecho/access.log
**6.4、MySQL 关闭公网访问 **
bash
#安全提醒:MySQL 3306 对公网开放的风险:
任何人都能尝试连接你的数据库
可能被暴力破解密码
数据泄露风险
#建议:
如果不需要公网连数据库,删掉阿里云安全组对MySQL3360端口开放的公网IP规则
或者把授权对象改成特定IP,不要用公网IP
#删掉这条规则,安全组MySQL仅内网
协议:TCP
访问来源:你的公网IP
访问目的:MySQL(3306)
#MySQL用户仅本机访问
[root@rocky8 ~]#grep -i "host\|DB_HOST" /data/nginx/typecho/config.inc.php
'host' => '127.0.0.1',
#查看 MySQL 所有用户、他们能从哪登录、用什么方式认证
mysql> SELECT user,host,plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user | host | plugin |
+------------------+-----------+-----------------------+
| typecho | 127.0.0.1 | caching_sha2_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session | localhost | caching_sha2_password |
| mysql.sys | localhost | caching_sha2_password |
| root | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+
6.5、隐藏 Nginx 和 PHP 版本,减少攻击面
bash
[root@rocky8 ~]#vim /apps/nginx/conf/nginx.conf
http {
server_tokens off; #隐藏Nginx版本
location ~ \.php$ {
fastcgi_hide_header X-Powered-By; #隐藏PHP版本
}
}
6.6、添加Nginx 安全头,防 XSS、点击劫持
bash
[root@rocky8 ~]#vim /apps/nginx/conf/conf.d/typecho.conf
#在 server { 块内,root 和 index 后面,location / 前面添加:
server {
root /data/nginx/typecho;
index index.php index.html;
#在这里加
add_header X-Frame-Options "SAMEORIGIN" always; #防点击劫持(Clickjacking)
add_header X-Content-Type-Options "nosniff" always; #防MIME 嗅探攻击
add_header X-XSS-Protection "1; mode=block" always; #防跨站脚本攻击(XSS)
add_header Referrer-Policy "strict-origin-when-cross-origin" always; #防信息泄露(不暴露完整URL)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
#在这里结束
location / {
}
[root@rocky8 ~]#nginx -t
[root@rocky8 ~]#nginx -s reload
6.7、网站后台仅内网访问
bash
[root@rocky8 ~]#vim /apps/nginx/conf/nginx.conf
# 后台入口 pipixia2026(仅本机127.0.0.1访问)
location ^~ /pipixia2026/ {
root /data/nginx/typecho;
index index.php;
allow 127.0.0.1;
deny all;
if (!-e $request_filename) {
rewrite^/pipixia2026/(.*)$ /pipixia2026/index.php?$1 last;
}
}
[root@rocky8 ~]#nginx -t
[root@rocky8 ~]#nginx -s reload
#在 Xshell 中操作
打开 Xshell →属性 →隧道 →添加
填写:
类型:本地(Outgoing)
源主机:127.0.0.1
侦听端口:8080
目标主机:127.0.0.1
目标端口:80
点击确定,保持 Xshell 连接不断
本地浏览器打开:
http://127.0.0.1:8080/pipixia2026/
就能看到 Typecho 登录页面了!
#302 是完全正常的:
你访问 /pipixia2026/
↓
Typecho 检测:用户未登录(没有session)
↓
302 重定向 → /pipixia2026/login.php
↓
显示登录页面 ← 这就是你要看到的!
[root@rocky8 ~]#curl -I http://127.0.0.1/pipixia2026/
HTTP/1.1 302 Found
Server: nginx
Date: Fri, 24 Jul 2026 12:07:44 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Location: http://127.0.0.1/pipixia2026/login.php?referer=http%3A%2F%2F127.0.0.1%2Fpipixia2026%2F
[root@rocky8 ~]#curl -I http://127.0.0.1/pipixia2026/index.php
HTTP/1.1 302 Found
Server: nginx
Date: Fri, 24 Jul 2026 12:08:26 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Location: http://127.0.0.1/pipixia2026/login.php?referer=http%3A%2F%2F127.0.0.1%2Fpipixia2026%2Findex.php
#如果不想看到302,直接访问登录页:
[root@rocky8 ~]#curl -I http://127.0.0.1/pipixia2026/login.php
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 24 Jul 2026 12:09:03 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding