2026年11月12日

2026年11月12日

禁止 WordPress uploads 目錄執行 PHP 的方法

本文是日文原文的在地化版本。 閱讀日文原文

前言

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中加入 Deny from all,③Nginx 用location ~ /wp-content/uploads/.*\.php$搭配deny all,④用wp_handle_upload_prefilter掛鉤直接拒絕 PHP 上傳,⑤以每小時一次的 cron 監控 uploads 內的 PHP 檔案。

對 WordPress 有疑問嗎?本站營運方位於日本,僅以日文回覆。 聯絡我們(日文)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲