PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.0
Defender Security – Malware Scanner, Login Security & Firewall v6.2.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / security-tweaks / class-disable-xml-rpc.php

class-disable-xml-rpc.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.0, at src/component/security-tweaks/class-disable-xml-rpc.php

291 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Responsible for disabling XML-RPC functionality in WordPress.
4 *
5 * @package WP_Defender\Component\Security_Tweaks
6 */
7
8 namespace WP_Defender\Component\Security_Tweaks;
9
10 use WP_Defender\Traits\IO;
11 use WP_Defender\Behavior\WPMUDEV;
12
13 /**
14 * XML-RPC can be a security risk if not properly managed, and this class provides methods to disable it and ensure it
15 * remains disabled.
16 */
17 class Disable_XML_RPC extends Abstract_Security_Tweaks {
18
19 use IO;
20
21 /**
22 * Unique identifier for the tweak.
23 *
24 * @var string $slug
25 */
26 public string $slug = 'disable-xml-rpc';
27
28 /**
29 * Indicates whether the issue has been resolved.
30 *
31 * @var bool
32 */
33 public bool $resolved = false;
34
35 /**
36 * This class contains everything relate to WPMUDEV.
37 *
38 * @var WPMUDEV|null
39 */
40 private ?WPMUDEV $wpmudev;
41
42 /**
43 * Class constructor to initialize the Disable_XML_RPC component.
44 *
45 * @return void
46 */
47 public function __construct() {
48 $this->wpmudev = wd_di()->get( WPMUDEV::class );
49 }
50
51 /**
52 * This function processes the request to disable XML-RPC.
53 *
54 * @return bool Returns true if the function successfully executes.
55 */
56 public function process(): bool {
57 // Update the site option for the current instance of the class to "ON".
58 update_site_option( $this->slug, 'ON' );
59
60 // Return true to indicate that the function executed successfully.
61 return true;
62 }
63
64 /**
65 * Reverts the XML-RPC toggle to the "off" state.
66 *
67 * @return bool Returns true if the function successfully executes.
68 */
69 public function revert(): bool {
70 // Set the XML-RPC toggle to "OFF".
71 update_site_option( $this->slug, 'OFF' );
72
73 // Return true to indicate that the function executed successfully.
74 return true;
75 }
76
77 /**
78 * Shield up. It runs on every page load when xml-rpc is disabled.
79 *
80 * @return void
81 */
82 public function shield_up(): void {
83 // Check if this tweak has been enabled.
84 $this->resolved = $this->check();
85 // if this tweak is ON, block XML-RPC.
86 if ( $this->resolved ) {
87 $this->add_hooks();
88 }
89 }
90
91 /**
92 * Queue hooks when this class init.
93 *
94 * @return void
95 */
96 public function add_hooks(): void {
97 // Disable XML-RPC methods that require authentication.
98 add_filter( 'xmlrpc_enabled', '__return_false' );
99 // Class used for handling XML-RPC requests.
100 add_filter( 'wp_xmlrpc_server_class', array( $this, 'handle_send_forbidden_response' ) );
101 // Methods exposed by the XML-RPC server.
102 add_filter( 'xmlrpc_methods', '__return_empty_array' );
103 }
104
105 /**
106 * Check whether the issue has been resolved or not.
107 *
108 * @return bool
109 */
110 public function check(): bool {
111 return $this->is_tweak_enabled_in_site();
112 }
113
114 /**
115 * Re-check the XML-RPC status.
116 *
117 * @return bool
118 */
119 public function recheck(): bool {
120 // Check if XML-RPC is disabled on Defender (plugin) side.
121 $plugin_xmlrpc_status = $this->is_tweak_enabled_in_site();
122 // Check if user is using WPMUDEV hosting.
123 if ( $this->wpmudev->is_wpmu_hosting() ) {
124 return $this->determine_status( $plugin_xmlrpc_status, $this->is_tweak_enabled_in_server() ) !== 3;
125 }
126 // Return the status of XML-RPC.
127 return $plugin_xmlrpc_status;
128 }
129
130 /**
131 * Check whether the tweak is enabled or not in the site.
132 *
133 * @return bool
134 */
135 public function is_tweak_enabled_in_site(): bool {
136 return get_site_option( $this->slug ) === 'ON';
137 }
138
139 /**
140 * Check whether the tweak is enabled or not in the server.
141 *
142 * @return bool
143 */
144 public function is_tweak_enabled_in_server(): bool {
145 // Check if the current site is hosted by WPMU DEV.
146 if ( ! $this->wpmudev->is_wpmu_hosting() ) {
147 // If not, return true to indicate that the tweak is enabled by default.
148 return true;
149 }
150
151 $server_xmlrpc_status = defender_get_hosting_feature_state( 'xmlrpc_block' );
152 if ( '' === $server_xmlrpc_status ) {
153 // Something went wrong.
154 return false;
155 }
156 // Return whether the XML-RPC is enabled or disabled based on the XML-RPC status.
157 return ! $server_xmlrpc_status;
158 }
159
160 /**
161 * Determines the status of the XML-RPC feature based on plugin and hosting settings.
162 *
163 * @param bool $is_plugin_xmlrpc_enabled Indicates if the plugin's XML-RPC is enabled.
164 * @param bool $is_hosting_xmlrpc_enabled Indicates if the hosting's XML-RPC is enabled.
165 *
166 * @return int The status of the XML-RPC feature.
167 */
168 public function determine_status( bool $is_plugin_xmlrpc_enabled, bool $is_hosting_xmlrpc_enabled ): int {
169 if ( $is_plugin_xmlrpc_enabled && ! $is_hosting_xmlrpc_enabled ) {
170 return 1; // Case 1: Defender ON, Hosting OFF.
171 }
172
173 if ( ! $is_plugin_xmlrpc_enabled && $is_hosting_xmlrpc_enabled ) {
174 return 2; // Case 2: Defender OFF, Hosting ON.
175 }
176
177 if ( ! $is_plugin_xmlrpc_enabled && ! $is_hosting_xmlrpc_enabled ) {
178 return 3; // Case 3: Defender OFF, Hosting OFF.
179 }
180
181 // If ON both sides then turn it OFF on Defender side.
182 $this->revert();
183 return 2; // Case 2: Defender OFF, Hosting ON.
184 }
185
186 /**
187 * Send a 403 Forbidden response and terminate the script.
188 *
189 * @return void
190 */
191 public function send_forbidden_response(): void {
192 http_response_code( 403 );
193 exit( esc_html__( 'Forbidden', 'defender-security' ) );
194 }
195
196 /**
197 * Wraps the send_forbidden_response method to fix PHPStan error.
198 *
199 * @param string $callback_class Class name passed by the filter.
200 */
201 public function handle_send_forbidden_response( string $callback_class ): string {
202 $this->send_forbidden_response();
203
204 // Unreachable, but required for PHPStan. Return the class name to satisfy the filter's expected return type.
205 return $callback_class;
206 }
207
208 /**
209 * Retrieve the tweak's label.
210 *
211 * @return string
212 */
213 public function get_label(): string {
214 return esc_html__( 'Turn off XML-RPC', 'defender-security' );
215 }
216
217 /**
218 * Get the error reason.
219 *
220 * @return string
221 */
222 public function get_error_reason(): string {
223 return esc_html__( 'XML-RPC is currently enabled.', 'defender-security' );
224 }
225
226 /**
227 * Return a summary data of this tweak.
228 *
229 * @return array
230 */
231 public function to_array(): array {
232 // The message to display if the XML-RPC feature is disabled.
233 $enabled = wp_strip_all_tags( __( 'XML-RPC is turned off.', 'defender-security' ) );
234 // Determine if the XML-RPC feature is enabled on the server side.
235 $in_server = $this->is_tweak_enabled_in_server();
236 // Determine if the XML-RPC feature is enabled on the plugin side.
237 $in_site = $this->is_tweak_enabled_in_site();
238
239 // If the site is not hosted on WPMU DEV's hosting, return the summary data.
240 if ( $this->wpmudev->is_wpmu_hosting() && $this->wpmudev->is_dash_activated() && $this->wpmudev->get_site_id() ) {
241 // If the site is hosted on WPMU DEV's hosting, construct the URL to the hosting settings page.
242 $url = 'https://wpmudev.com/hub2/site/' . $this->wpmudev->get_site_id() . '/hosting/tools#block-xml-rpc';
243
244 $hosting_settings_url = null;
245
246 // If the XML-RPC feature is enabled on the server side, construct the message to display.
247 if ( $in_server ) {
248 if ( $this->wpmudev->is_whitelabel_enabled() ) {
249 $enabled = wp_strip_all_tags( __( 'You can manage the XML-RPC settings in the Hosting Settings.', 'defender-security' ) );
250 } else {
251 $enabled = ''; // React composes this string via createInterpolateElement using hosting_settings_url.
252 $hosting_settings_url = $url;
253 }
254 } elseif ( $this->wpmudev->is_whitelabel_enabled() ) {
255 $enabled = wp_strip_all_tags( __( 'XML-RPC is currently disabled on plugin side.', 'defender-security' ) );
256 } else {
257 $enabled = wp_strip_all_tags( __( 'XML-RPC is currently disabled on plugin side, we suggest disabling it from server side by clicking on this link.', 'defender-security' ) );
258 $hosting_settings_url = $url;
259 }
260
261 // Return the summary data.
262 return array(
263 'slug' => $this->slug,
264 'title' => $this->get_label(),
265 'errorReason' => $this->get_error_reason(),
266 'successReason' => $enabled,
267 'misc' => array(
268 'show_revert_button' => ! $in_server,
269 'hosting_settings_url' => $hosting_settings_url,
270 'show_action_button' => true,
271 ),
272 'bulk_description' => wp_strip_all_tags( __( 'XML-RPC lets you publish to your WordPress site remotely using apps like the mobile app or services like IFTTT. If you don’t use remote publishing, turn off XML-RPC to help reduce security risk.', 'defender-security' ) ),
273 'bulk_title' => 'XML-RPC',
274 );
275 }
276
277 return array(
278 'slug' => $this->slug,
279 'title' => $this->get_label(),
280 'errorReason' => $this->get_error_reason(),
281 'successReason' => $enabled,
282 'misc' => array(
283 'show_revert_button' => $in_site,
284 'show_action_button' => true,
285 ),
286 'bulk_description' => wp_strip_all_tags( __( 'XML-RPC lets you publish to your WordPress site remotely using apps like the mobile app or services like IFTTT. If you don’t use remote publishing, turn off XML-RPC to help reduce security risk.', 'defender-security' ) ),
287 'bulk_title' => 'XML-RPC',
288 );
289 }
290 }
291