wordpress 修補使用者外洩漏洞

請將下面內容完整寫入外掛檔案。

<?php
/*
Plugin Name: Security Hardening
Description: Block WordPress author enumeration.
Version: 1.1
*/

defined('ABSPATH') || exit;

/**
 * 提前攔截 ?author=1、?author=2 等帳號列舉。
 */
add_action('parse_request', function ($wp) {
    if (is_admin()) {
        return;
    }

    if (
        isset($_GET['author']) &&
        is_scalar($_GET['author']) &&
        preg_match('/^\d+$/', (string) $_GET['author'])
    ) {
        wp_safe_redirect(home_url('/'), 302);
        exit;
    }
}, 1);

/**
 * 阻擋 /author/帳號名稱/ 作者彙整頁。
 */
add_action('template_redirect', function () {
    if (!is_admin() && is_author()) {
        wp_safe_redirect(home_url('/'), 302);
        exit;
    }
}, 1);

/**
 * 防止 WordPress 將 ?author=1 自動轉成 /author/帳號名稱/。
 */
add_filter('redirect_canonical', function ($redirect_url, $requested_url) {
    if (
        isset($_GET['author']) &&
        is_scalar($_GET['author']) &&
        preg_match('/^\d+$/', (string) $_GET['author'])
    ) {
        return false;
    }

    return $redirect_url;
}, 1, 2);

parse_request 會在 WordPress 完成網址與查詢變數解析後執行,適合提前辨識 author 請求;template_redirect 則是在載入前端模板前執行,可利用 is_author() 判斷作者頁。

檔案位置

確認檔案是:

wp-content/plugins/security-hardening/security-hardening.php

目錄結構應為:

wp-content/
└── plugins/
    └── security-hardening/
        └── security-hardening.php

修改後到 WordPress 後台:

外掛 → 已安裝的外掛

先停用 Security Hardening,再重新啟用。

驗證方式

請使用瀏覽器無痕模式測試:

https://你的網址/?author=1

以及:

https://你的網址/author/已知帳號名稱/

兩者都應該回到首頁。

也可以用指令確認:

curl -I "https://你的網址/?author=1"

預期看到:

HTTP/2 302
location: https://你的網址/

若仍無效

很可能是快取造成,請清除:

  • WordPress 快取外掛
  • Nginx FastCGI Cache
  • Cloudflare Cache
  • 主機商頁面快取
  • 瀏覽器快取

測試時也可以加隨機參數:

https://你的網址/?author=1&test=12345

另外要注意,這段程式只處理作者列舉,不會封鎖 REST API users。還要在同一個外掛加入:

add_filter('rest_endpoints', function ($endpoints) {
    unset($endpoints['/wp/v2/users']);
    unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);

    return $endpoints;
});

再測試:

https://你的網址/wp-json/wp/v2/users

正常應回傳:

{
  "code": "rest_no_route"
}

docker-compose來快速建置wordpress

以docker-compose.yml來建置wordpress服務於8031 port,並且加上 phpMyAdmin,讓你用瀏覽器管理同一個 MySQL。WordPress 仍然以 8031 對外,phpMyAdmin 另外用 8032

version: '3.9'

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress_site
    ports:
      - "8031:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppassword
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db
    restart: always

  db:
    image: mysql:5.7
    container_name: wordpress_db
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppassword
    volumes:
      - db_data:/var/lib/mysql
    restart: always

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: wp_phpmyadmin
    depends_on:
      - db
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
      PMA_USER: root
      PMA_PASSWORD: rootpassword
      UPLOAD_LIMIT: 512M
    ports:
      - "8032:80"
    restart: always

volumes:
  wordpress_data:
  db_data:

使用方式

  1. 將上面內容存成 docker-compose.yml
  2. 啟動: docker-compose up -d
  3. 開啟:
    • WordPress:http://localhost:8031
    • phpMyAdmin:http://localhost:8032(使用 root / rootpasswordwpuser / wppassword 登入)

建議:上線前把 rootpassword / wppassword 換成強密碼;若要改用 MariaDB 也可以把 db 的 image 換成 mariadb:10.11,其餘設定相同。