2026年11月12日
2026年11月12日
禁止 WordPress uploads 目录执行 PHP 的方法(.htaccess / Nginx)
本文是日语原文的本地化版本。 阅读日语原文
前言
wp-content/uploads/ 是 WordPress 保存图片等媒体文件的目录。如果这个目录中被放置了 PHP 文件,并且处于可以执行的状态,攻击者就可以上传 Web shell(后门),执行任意代码。
症状与原因
- 恶意软件扫描在
wp-content/uploads/内检测到了 PHP 文件 - 安全插件发出警告:“uploads 目录中可以执行 PHP”
- 发现了路径类似
wp-content/uploads/2024/01/shell.php的可疑文件 - 攻击者利用文件上传功能的漏洞,植入了 Web shell
解决步骤
步骤1:检测已有的可疑 PHP 文件
# 搜索 uploads 目录内的全部 PHP 文件
find /var/www/html/wp-content/uploads -name "*.php" -type f
find /var/www/html/wp-content/uploads -name "*.phtml" -type f
find /var/www/html/wp-content/uploads -name "*.php5" -type f
# 查看最近(7 天内)创建或更新的 PHP 文件
find /var/www/html/wp-content/uploads -name "*.php" -mtime -7
# 检查文件内容(恶意软件的典型特征)
grep -rl "eval(base64_decode" /var/www/html/wp-content/uploads/
grep -rl "system\|exec\|passthru\|shell_exec" /var/www/html/wp-content/uploads/
# 删除可疑的 PHP 文件
find /var/www/html/wp-content/uploads -name "*.php" -delete
find /var/www/html/wp-content/uploads -name "*.phtml" -delete
步骤2:在 Apache 中禁止执行 PHP(.htaccess)
# 创建 wp-content/uploads/.htaccess
cat > /var/www/html/wp-content/uploads/.htaccess << 'EOF'
# 彻底禁止执行 PHP 文件
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phar|shtml)$">
Order Deny,Allow
Deny from all
</FilesMatch>
# 直接禁用 PHP 引擎(使用 mod_php 时)
<IfModule mod_php.c>
php_flag engine off
</IfModule>
# 同时禁止执行 CGI
Options -ExecCGI
RemoveHandler .php .phtml .php5 .phar
# 同时禁用目录列表
Options -Indexes
EOF
chmod 644 /var/www/html/wp-content/uploads/.htaccess
# 设置后的确认
# 创建测试用的 PHP 文件并尝试访问
echo "<?php echo 'test'; ?>" > /var/www/html/wp-content/uploads/test_block.php
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/test_block.php
# 返回 403 即为成功
rm /var/www/html/wp-content/uploads/test_block.php
步骤3:在 Nginx 中禁止执行 PHP
# /etc/nginx/sites-available/example.com
server {
# ... 现有的配置 ...
# 禁止在 uploads 目录中执行 PHP
location ~* /wp-content/uploads/.*\.(php|phtml|php5|phar)$ {
deny all;
access_log off;
log_not_found off;
}
# 必须写在 PHP-FPM 的 location 之前
location ~ \.php$ {
# 常规的 PHP 处理
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
# 检查 Nginx 配置并使其生效
sudo nginx -t && sudo systemctl reload nginx
# 确认
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/shell.php
# 返回 403 即为成功
步骤4:同时在 WordPress 中拦截 PHP 上传
// functions.php:禁止上传 PHP 文件本身
// ① 把 PHP 扩展名加入禁止上传的列表
add_filter('upload_mimes', function(array $mimes): array {
// 移除与 PHP 相关的 MIME 类型(以防万一)
unset($mimes['php'], $mimes['phtml'], $mimes['phar']);
return $mimes;
});
// ② 检测并拒绝上传文件中的 PHP
add_filter('wp_handle_upload_prefilter', function(array $file): array {
$dangerous_extensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'phar', 'shtml'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (in_array($ext, $dangerous_extensions, true)) {
$file['error'] = '禁止上传 PHP 文件。';
}
// 也通过 MIME 类型确认
if (str_contains($file['type'], 'php')) {
$file['error'] = '禁止上传 PHP 文件。';
}
return $file;
});
步骤5:设置定期监控
# 定期监控 uploads 内 PHP 文件的脚本
cat > /usr/local/bin/check-uploads-php.sh << 'EOF'
#!/bin/bash
UPLOADS_DIR="/var/www/html/wp-content/uploads"
ADMIN_EMAIL="admin@example.com"
PHP_FILES=$(find "$UPLOADS_DIR" -name "*.php" -o -name "*.phtml" -o -name "*.phar" 2>/dev/null)
if [ -n "$PHP_FILES" ]; then
echo "警告:在 uploads 目录中检测到 PHP 文件:
$PHP_FILES" | mail -s "[紧急] WordPress 上可能被植入了 Web shell" "$ADMIN_EMAIL"
# 自动删除(请谨慎使用)
# find "$UPLOADS_DIR" -name "*.php" -delete
fi
EOF
chmod +x /usr/local/bin/check-uploads-php.sh
# 每小时检查一次
echo "0 * * * * root /usr/local/bin/check-uploads-php.sh" > /etc/cron.d/wp-uploads-php-check
注意事项
- 通过
.htaccess设置的php_flag engine off仅在使用mod_php时有效。如果使用的是php-fpm(FastCGI),请用指令或 Nginx 的 location 块来处理 - 在 Nginx 中,如果不把 uploads 的拦截规则写在
location ~ \.php$之前,后者可能会优先生效,导致仍然可以执行。请务必把拦截规则放在更靠前的位置 - 部分插件(例如 Slider Revolution 等)可能会在 uploads 内放置
.php文件。删除之前请先确认其用途,并在删除不需要的插件之后再进行处理
总结
禁止 uploads 目录执行 PHP,按以下步骤进行:①用 find wp-content/uploads -name ".php" 检测并删除已有的可疑文件;②Apache 在 uploads/.htaccess 中追加 ;③Nginx 用 location ~ /wp-content/uploads/.*\.php$ 配置 deny all;④通过 wp_handle_upload_prefilter 钩子拒绝 PHP 文件本身的上传;⑤用每小时一次的 cron 监控 uploads 内的 PHP 文件。
关于 WordPress 有疑问?本站运营方位于日本,仅以日语回复。 联系我们(日语)