Tắt API REST của WordPress mà không có plugin

Theo mặc định, API REST của WordPress được bật và điều này có thể khiến trang web của bạn bị rò rỉ dữ liệu liên hệ của người dùng. Ở đây, chúng tôi sẽ vô hiệu hóa quyền truy cập vào API REST mà không cần sử dụng plugin. Để xem điều gì đang xảy ra với REST API, hãy thử URL sau trong trình duyệt (thay thế www.example.org bằng miền của trang web của bạn):

https://www.example.org/wp-json/wp/v2/users

Bạn thực sự có thể sử dụng một plugin được tạo sẵn để tắt API REST của WordPress. Tuy nhiên, điều đó hơi quá dễ dàng, vì vậy… để tránh tải nhiều plugin, chúng tôi sẽ thêm một chút mã vào tệp functions.php của chủ đề của chúng tôi.

Chúng tôi sẽ giới thiệu một số cách để ảnh hưởng đến API REST:

  • Tắt hoàn toàn API REST.
  • Chỉ cho phép API REST cho người dùng đã đăng nhập và địa chỉ IP có trong danh sách cho phép.
  • Cung cấp API REST cho mọi người (giống như cách WordPress hoạt động bình thường) nhưng vô hiệu hóa tính năng liệt kê người dùng.
  • Nếu API REST không có sẵn (hoặc điểm cuối bị từ chối) thay vì hiển thị một trang trống, chúng tôi sẽ chuyển hướng người dùng đến trang 404 thích hợp của bạn. Đó là một chi tiết hay 😎
  • Như một phần bổ sung, chúng tôi có thể ghi vào nhật ký xác thực hệ thống để Fail2Ban có thể chặn địa chỉ IP từ xa ở cấp tường lửa 😎😎

Hãy viết mã

Đầu tiên, tạo một tệp mới trong thư mục chủ đề con tùy chỉnh của bạn có tên là functions-rest-api.php . Điều này sẽ cho phép chúng tôi giữ các chức năng API REST mới của chúng tôi tách biệt với bất kỳ thứ gì khác mà bạn đã thực hiện trong tệp functions.php chính của mình. Nó cũng giúp bạn dễ dàng sử dụng lại các công cụ mới này trên các trang web khác.

Dán phần sau vào tệp functions-rest-api.php mới .

/**
 * By default, the REST API is enabled - like the default WordPress behaviour.
 *
 * If you want to disable the API completely for non-logged-in users then just
 * call hw_completely_disable_rest_api(), BUT BUT BUT, you probably just want
 * to add this to your functions.php
 *
 *   define('HW_IS_REST_API_USER_ENUMERATION_DISABLED', true);
 *
 * If you want to only allow REST API calls for non-logged-in users from
 * certain IP addresses, just pass those IP addresses in the constant
 * HW_REST_API_IP_WHITELIST, like this:
 *
 *  define(
 *     'HW_REST_API_IP_WHITELIST',
 *     array('127.0.0.1', '::1', 'address-1', 'address-2', '...')
 *  );
 *
 * If you want to write events to the system auth log for Fail2Ban to see, then:
 *
 *  define('HW_REST_IS_FAIL2BAN_ENABLED', true);
 *
 */
// Block direct access.
if (!defined('WPINC')) {
   exit('Do NOT access this file directly.');
}
define('HW_REST_API_DEFAULT_IP_WHITELIST', array('127.0.0.1', '::1'));
function hw_completely_disable_rest_api() {
   if (!defined('HW_IS_REST_API_DISABLED')) {
      define('HW_IS_REST_API_DISABLED', true);
   }
}
function hw_disable_rest_api_user_enumeration() {
   if (!defined('HW_IS_REST_API_USER_ENUMERATION_DISABLED')) {
      define('HW_IS_REST_API_USER_ENUMERATION_DISABLED', true);
   }
}
function hw_request_block_ip($ip_address = '') {
   if (empty($ip_address)) {
      $ip_address = sanitize_text_field($_SERVER['REMOTE_ADDR']);
   }
   if (!empty($ip_address)) {
      // error_log('Blocking IP: ' . $ip_address);
      $is_fail2ban_enabled = true;
      if (defined('HW_REST_IS_FAIL2BAN_ENABLED') && (HW_REST_IS_FAIL2BAN_ENABLED !== true)) {
         $is_fail2ban_enabled = false;
      }
      if ($is_fail2ban_enabled) {
         openlog('wp(' . sanitize_text_field($_SERVER['HTTP_HOST']) . ')', LOG_NDELAY | LOG_PID, LOG_AUTH);
         syslog(LOG_INFO, "REST User Enum " . $ip_address);
         closelog();
      } else {
         error_log('Found enumeration attempt, but HW_REST_IS_FAIL2BAN_ENABLED is not enabled.');
      }
   }
}
function hw_rest_api_init() {
   $is_rest_api_available = true;
   $is_attempting_user_enumeration = false;
   $is_user_an_administrator = false;
   if ($is_user_authenticated = is_user_logged_in()) {
      $is_user_an_administrator = current_user_can('administrator');
   }
   $is_user_authorised = ($is_user_authenticated && $is_user_an_administrator);
   $is_remote_ip_whitelisted = false;
   if (defined('HW_REST_API_IP_WHITELIST') && is_array(HW_REST_API_IP_WHITELIST)) {
      $is_remote_ip_whitelisted = in_array($_SERVER['REMOTE_ADDR'], HW_REST_API_IP_WHITELIST);
   } elseif (defined('HW_REST_API_DEFAULT_IP_WHITELIST') && is_array(HW_REST_API_DEFAULT_IP_WHITELIST)) {
      $is_remote_ip_whitelisted = in_array($_SERVER['REMOTE_ADDR'], HW_REST_API_DEFAULT_IP_WHITELIST);
   } else {
      // ...
   }
   $is_ip_block_requested = false;
   $is_rest_api_disabled = false;
   if (defined('HW_IS_REST_API_DISABLED')) {
      $is_rest_api_disabled = (HW_IS_REST_API_DISABLED === true);
   }
   $is_public_user_enumeration_disabled = true;
   if (defined('HW_IS_REST_API_USER_ENUMERATION_DISABLED') && (HW_IS_REST_API_USER_ENUMERATION_DISABLED !== true)) {
      $is_public_user_enumeration_disabled = false;
   }
   $is_endpoint_blocked = false;
   if (!$is_user_authenticated && !$is_remote_ip_whitelisted && $is_public_user_enumeration_disabled) {
      $prefix = rest_get_url_prefix();
      $users_path = '/' . $prefix . '/wp/v2/users';
      if ((isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], $users_path) !== false))
         ||
         (isset($_REQUEST['rest_route']) && (strpos($_SERVER['rest_route'], $users_path) !== false))
      ) {
         $is_endpoint_blocked = true;
         $is_ip_block_requested = true;
      }
   }
   $http_error_code = null;
   $is_rest_api_available = false;
   if ($is_user_authorised) {
      // ...
   } elseif ($is_remote_ip_whitelisted) {
      // ...
   } elseif ($is_rest_api_disabled) {
      $http_error_code = 404;
   } elseif (!$is_endpoint_blocked) {
      // ...
   } else {
      $http_error_code = 404;
   }
   if ($is_ip_block_requested) {
      hw_request_block_ip();
   }
   if ($http_error_code == 404) {
      header("Status: 404 Not Found");
      $GLOBALS['wp_query']->set_404();
      status_header(404);
      nocache_headers();
      include get_query_template('404');
      exit;
   } elseif (!empty($http_error_code)) {
      http_response_code($http_error_code);
      die('ERR: ' . $http_error_code);
   } else {
      // OK.
   }
}
add_action('rest_api_init', 'hw_rest_api_init', 100);

Ngay lập tức, bạn sẽ thấy chúng tôi có một số chức năng mới mà chúng tôi có thể sử dụng trong mã của mình:

  • hw_compleedly_disable_rest_api ()
  • hw_disable_rest_api_user_enumeration ()
Chúng tôi sẽ quay lại những điều này trong giây lát. Đầu tiên, hãy tham khảo mã mới của chúng tôi từ tệp functions.php chính. Thêm đoạn mã sau vào đâu đó gần đầu functions.php trong chủ đề con tùy chỉnh của bạn.
// Load functions to adjust visibility of the REST API.
require_once 'functions-rest-api.php';
Ngay lập tức, bạn sẽ thấy chúng tôi có một số chức năng mới mà chúng tôi có thể sử dụng trong mã của mình:
  • hw_compleedly_disable_rest_api ()
  • hw_disable_rest_api_user_enumeration ()
Chúng tôi sẽ quay lại những điều này trong giây lát. Đầu tiên, hãy tham khảo mã mới của chúng tôi từ tệp functions.php chính. Thêm đoạn mã sau vào đâu đó gần đầu functions.php trong chủ đề con tùy chỉnh của bạn.
// Load functions to adjust visibility of the REST API.
require_once 'functions-rest-api.php';
Bây giờ chúng tôi đã sẵn sàng để gọi mã và chạy một số thử nghiệm để chứng minh nó đang hoạt động.

Sử dụng các chức năng mới

Mã này khá dễ sử dụng. Nếu bạn muốn tắt hoàn toàn API REST, chỉ cần thêm phần sau vào đâu đó trong tệp functions.php của bạn.
/**
 * Completely disable the REST API for non-logged-in users.
 * Logged-in users will still have access to the API.
 */
hw_completely_disable_rest_api();
Bạn có thể kiểm tra điều này bằng cách đặt URL sau vào trình duyệt của mình.
https://www.example.org/wp-json/wp/v2/users
Nếu mọi thứ hoạt động bình thường thì bạn nên chuyển hướng đến trang 404 Not Found trên trang web của bạn.

NHƯNG, NHƯNG, NHƯNG . Bạn có thể không muốn làm điều này. Nếu bạn đã cài đặt Biểu mẫu liên hệ 7 trên trang web của mình thì điều này có thể phá vỡ biểu mẫu. Vì vậy, đây là nơi chúng ta cần phải phẫu thuật nhiều hơn một chút. Thay vì gọi hw_compleedly_disable_rest_api (), hãy thử thêm phần sau:

/**
 * Disable user-enumeration in the REST API. Either of these methods
 * should work fine.
 */
hw_disable_rest_api_user_enumeration();

Bây giờ, hãy thử truy cập URL liệt kê người dùng và bạn sẽ thấy một thông báo lỗi khác. Trên thực tế, bạn sẽ nhận được phản hồi 404 Not Found, vì hàm xử lý bộ lọc hw_rest_endpoints () của chúng tôi đã xóa các điểm cuối khỏi API. Đó là một chút rõ ràng hơn là chỉ tắt tất cả.

Việc sử dụng cuối cùng là vô hiệu hóa API REST cho những người dùng chưa đăng nhập, ngoại trừ những người dùng kết nối từ các địa chỉ IP cụ thể. Để thực hiện việc này, thay vì gọi một trong các hàm mới, chúng ta chỉ cần thiết lập một hằng số chứa một mảng các địa chỉ hợp lệ, như sau:

/**
 * Completely disable the REST API for non-logged-in users,
 * unless connecting from a valid IP address.
 */
define(
   'HW_REST_API_IP_WHITELIST',
   array('127.0.0.1', '::1')
);

Bạn có thể muốn bao gồm ‘127.0.0.1’ và ‘:: 1’ trong danh sách địa chỉ IP của mình, để máy chủ có thể kết nối với chính nó. Chỉ cần nối các địa chỉ IP trong danh sách trắng khác của bạn vào cuối mảng.

Kết thúc

Sau tất cả những điều đó, trong hầu hết các trường hợp, bạn sẽ chỉ muốn làm điều này:
  1. Tạo tệp functions-rest-api.php với mã ở trên.
  2. Bao gồm tệp này từ tệp functions.php của chủ đề con tùy chỉnh của bạn bằng cách sử dụng request_once.
  3. Gọi hw_disable_rest_api_user_enumeration () từ một nơi nào đó trong tệp functions.php của bạn.
Đó là nó. Đã đến lúc REST.