PluginProbe ʕ •ᴥ•ʔ
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) / 9.5.9
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) v9.5.9
9.5.11 9.5.10.1 9.5.10 trunk 9.4.0 9.4.1 9.4.2 9.4.3 9.5.0 9.5.0.1 9.5.0.2 9.5.1 9.5.2 9.5.2.2 9.5.2.3 9.5.3 9.5.3.1 9.5.3.2 9.5.4 9.5.5 9.5.6 9.5.7 9.5.8 9.5.9
really-simple-ssl / class-site-health.php
really-simple-ssl Last commit date
assets 2 months ago core 2 months ago languages 2 months ago lets-encrypt 2 months ago lib 2 months ago mailer 2 months ago modal 2 months ago placeholders 2 months ago progress 2 months ago security 2 months ago settings 2 months ago testssl 2 months ago upgrade 2 months ago .wp-env.json 2 months ago SECURITY.md 2 months ago class-admin.php 2 months ago class-cache.php 2 months ago class-certificate.php 2 months ago class-front-end.php 2 months ago class-installer.php 2 months ago class-mixed-content-fixer.php 2 months ago class-multisite.php 2 months ago class-server.php 2 months ago class-site-health.php 2 months ago class-wp-cli.php 2 months ago compatibility.php 2 months ago force-deactivate.txt 2 months ago functions.php 2 months ago index.php 2 months ago readme.txt 2 months ago rector.php 2 months ago rlrsssl-really-simple-ssl.php 2 months ago rsssl-auto-loader.php 2 months ago sbom.json.gz 2 months ago ssl-test-page.php 2 months ago system-status.php 2 months ago uninstall.php 2 months ago upgrade.php 2 months ago
class-site-health.php
374 lines
1 <?php defined( 'ABSPATH' ) or die();
2
3 if ( ! class_exists( 'rsssl_site_health' ) ) {
4 class rsssl_site_health {
5 private static $_this;
6 public function __construct() {
7
8 if ( isset( self::$_this ) ) {
9 wp_die( 'you cannot create a second instance.' );
10 }
11
12 add_filter( 'site_status_tests', array( $this, 'health_check' ), 1, 10 );
13 self::$_this = $this;
14 }
15
16 public static function this() {
17 return self::$_this;
18 }
19
20
21 /**
22 * Add SSL dedicated health check
23 * @param array $tests
24 *
25 * @return array
26 */
27 public function health_check( $tests ) {
28 unset( $tests['async']['https_status'] );
29 if ( ! rsssl_get_option( 'dismiss_all_notices' ) ) {
30 $tests['direct']['rsssl_ssl_health'] = array(
31 'label' => __( 'SSL Status Test', 'really-simple-ssl' ),
32 'test' => array( $this, 'ssl_tests' ),
33 );
34
35 $tests['direct']['headers_test'] = array(
36 'label' => __( 'Security Headers Test', 'really-simple-ssl' ),
37 'test' => array( $this, 'headers_test' ),
38 );
39
40 unset( $tests['direct']['debug_enabled'] );
41 if ( rsssl_is_debugging_enabled() && rsssl_debug_log_value_is_default() ) {
42 $tests['direct']['rsssl_debug_log'] = array(
43 'test' => array( $this, 'site_health_debug_log_test' ),
44 );
45 }
46
47 if ( rsssl_maybe_disable_404_blocking() ) {
48 $tests['direct']['rsssl_404_test'] = array(
49 'test' => array( $this, 'site_health_404_display' ),
50 );
51 }
52 // Two-Factor Authentication (2FA) test
53 $tests['direct']['rsssl_2fa_test'] = array(
54 'label' => __( 'Two-Factor Authentication', 'really-simple-ssl' ),
55 'test' => array( $this, 'two_factor_auth_test' ),
56 );
57
58 // Limit Login Attempts (LLA) test
59 $tests['direct']['rsssl_lla_test'] = array(
60 'label' => __( 'Limit Login Attempts Protection', 'really-simple-ssl' ),
61 'test' => array( $this, 'limit_login_attempts_test' ),
62 );
63
64 // Firewall Protection test
65 $tests['direct']['rsssl_firewall_test'] = array(
66 'label' => __( 'Firewall Protection', 'really-simple-ssl' ),
67 'test' => array( $this, 'firewall_test' ),
68 );
69
70 }
71
72 return $tests;
73 }
74
75 /**
76 * Test for Two-Factor Authentication (2FA)
77 * @return array
78 */
79 public function two_factor_auth_test() {
80 $status = 'recommended';
81 $description = __( 'We recommend to enable Two-Factor Authentication at least for administrators.', 'really-simple-ssl' );
82
83 // Check if RSSSL 2FA, WordFence, Solid Security, AIOS are installed and 2FA is enabled
84 if ( rsssl_get_option('login_protection_enabled') == '1' || is_plugin_active('wordfence/wordfence.php') || is_plugin_active('two-factor/two-factor.php') || is_plugin_active('all-in-one-wp-security-and-firewall/wp-security.php') || is_plugin_active('better-wp-security/better-wp-security.php') ) {
85 $status = 'good';
86 $description = __( 'Your site is protected by Two-Factor Authentication (2FA).', 'really-simple-ssl' );
87 }
88
89 return array(
90 'label' => __( 'Protect your user logins with Two-Factor Authentication (at least for Administrator accounts)', 'really-simple-ssl' ),
91 'status' => $status,
92 'badge' => array(
93 'label' => __( 'Security', 'really-simple-ssl' ),
94 'color' => 'blue',
95 ),
96 'description' => sprintf( '<p>%s</p>', $description ),
97 'actions' => sprintf(
98 '<p><a href="%s" target="_blank">%s</a></p>',
99 esc_url( admin_url( 'admin.php?page=really-simple-security#settings/two-fa' ) ),
100 __( 'Read more', 'really-simple-ssl' )
101 ),
102 'test' => 'rsssl_2fa_test',
103 );
104 }
105
106 /**
107 * Test for Limit Login Attempts (LLA)
108 * @return array
109 */
110 public function limit_login_attempts_test() {
111 $status = 'recommended';
112 $description = __( 'Enable Limit Login Attempts to protect the login form against brute-force attacks.', 'really-simple-ssl' );
113
114 // Check if RSSSL LLA or Limit Login Attempts Reloaded is installed and active
115 if ( rsssl_get_option('enable_limited_login_attempts') == '1' || is_plugin_active('wordfence/wordfence.php') || is_plugin_active('limit-login-attempts-reloaded/limit-login-attempts-reloaded.php') || is_plugin_active('better-wp-security/better-wp-security.php') ) {
116 $status = 'good';
117 $description = __( 'Your site is protected by Limit Login Attempts.', 'really-simple-ssl' );
118 }
119
120 return array(
121 'label' => __( 'Protect your login form with Limit Login Attempts', 'really-simple-ssl' ),
122 'status' => $status,
123 'badge' => array(
124 'label' => __( 'Security', 'really-simple-ssl' ),
125 'color' => 'blue',
126 ),
127 'description' => sprintf( '<p>%s</p>', $description ),
128 'actions' => sprintf(
129 '<p><a href="%s" target="_blank">%s</a></p>',
130 esc_url( admin_url( 'admin.php?page=really-simple-security#settings/limit_login_attempts' ) ),
131 __( 'Read more', 'really-simple-ssl' )
132 ),
133 'test' => 'rsssl_lla_test',
134 );
135 }
136
137 /**
138 * Test for Firewall Protection
139 * @return array
140 */
141 public function firewall_test() {
142 $status = 'recommended';
143 $description = __( 'Secure your site with the performant Firewall.', 'really-simple-ssl' );
144
145 // Check if WordFence, AIOS, or Solid Security is installed
146 if ( rsssl_get_option('enable_firewall') || is_plugin_active('wordfence/wordfence.php') || is_plugin_active('all-in-one-wp-security-and-firewall/wp-security.php') || is_plugin_active('better-wp-security/better-wp-security.php') ) {
147 $status = 'good';
148 $description = __( 'Your site is protected by a firewall.', 'really-simple-ssl' );
149 }
150
151 return array(
152 'label' => __( 'Secure your site with a Firewall', 'really-simple-ssl' ),
153 'status' => $status,
154 'badge' => array(
155 'label' => __( 'Security', 'really-simple-ssl' ),
156 'color' => 'blue',
157 ),
158 'description' => sprintf( '<p>%s</p>', $description ),
159 'actions' => sprintf(
160 '<p><a href="%s" target="_blank">%s</a></p>',
161 esc_url( admin_url( 'admin.php?page=really-simple-security#settings/firewall' ) ),
162 __( 'Read more', 'really-simple-ssl' )
163 ),
164 'test' => 'rsssl_firewall_test',
165 );
166 }
167
168 /**
169 * Generate the WP_DEBUG notice
170 *
171 */
172 public function site_health_debug_log_test() {
173 $result = array(
174 'label' => __( 'Your site is set to log errors to a potentially public file' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
175 'status' => 'recommended',
176 'badge' => array(
177 'label' => __( 'Security' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
178 'color' => 'blue',
179 ),
180 'description' => sprintf(
181 '<p>%s</p>',
182 __( 'The value, WP_DEBUG_LOG, has been added to this website’s configuration file. This means any errors on the site will be written to a file which is potentially available to all users.', 'really-simple-ssl' )
183 ),
184 'actions' => sprintf(
185 '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
186 /* translators: Documentation explaining debugging in WordPress. */
187 esc_url( rsssl_admin_url([], '#settings/hardening') ),
188 __( 'Remove from public location with Really Simple Security', 'really-simple-ssl' ),
189 /* translators: Accessibility text. */
190 __( '(opens in a new tab)' )// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
191 ),
192 'test' => 'rsssl_debug_log',
193 );
194
195 return $result;
196 }
197
198 /**
199 * Explain users about risks of debug display
200 *
201 */
202 public function site_health_debug_display_test() {
203 $result = array(
204 'label' => __( 'Your site is set to display errors on your website', 'really-simple-ssl' ),
205 'status' => 'critical',
206 'badge' => array(
207 'label' => __( 'Security' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
208 'color' => 'blue',
209 ),
210 'description' => sprintf(
211 '<p>%s</p>',
212 __( 'The value, WP_DEBUG_DISPLAY, has either been enabled by WP_DEBUG or added to your configuration file. This will make errors display on the front end of your site.', 'really-simple-ssl' )
213 ),
214 'actions' => sprintf(
215 '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
216 /* translators: Documentation explaining debugging in WordPress. */
217 esc_url( rsssl_link('security/debug-display-enabled') ),
218 __( 'Read more about security concerns with debug display enabled', 'really-simple-ssl' ),
219 /* translators: Accessibility text. */
220 __( '(opens in a new tab)' )// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
221 ),
222 'test' => 'rsssl_debug_display',
223 );
224
225 return $result;
226 }
227
228 /**
229 * Check for 404 errors.
230 *
231 */
232 public function site_health_404_display() {
233 $result = array(
234 'label' => __( '404 errors detected on your homepage', 'really-simple-ssl' ),
235 'status' => 'critical',
236 'badge' => array(
237 'label' => __( 'Security' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
238 'color' => 'blue',
239 ),
240 'description' => sprintf(
241 '<p>%s</p>',
242 __( '404 errors detected on your homepage. This means that the page requests images, scripts or other resources that are no longer available. It can interfere with your Firewall as well.', 'really-simple-ssl' )
243 ),
244 'actions' => sprintf(
245 '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
246 /* translators: Documentation explaining debugging in WordPress. */
247 esc_url( rsssl_link('404-not-found-errors') ),
248 __( 'Read more', 'really-simple-ssl' ),
249 /* translators: Accessibility text. */
250 __( '(opens in a new tab)' )// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
251 ),
252 'test' => 'rsssl_404_test',
253 );
254
255 return $result;
256 }
257
258 /**
259 * Test to check if the recommended security headers are present
260 * @return array
261 */
262
263 public function headers_test() {
264 $result = array(
265 'label' => __( 'Essential security headers installed', 'really-simple-ssl' ),
266 'status' => 'good',
267 'badge' => array(
268 'label' => __( 'Security' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
269 'color' => 'blue',
270 ),
271 'description' => sprintf(
272 '<p>%s</p>',
273 __( 'The essential security headers are detected on your site.', 'really-simple-ssl' )
274 ),
275 'actions' => '',
276 'test' => 'headers_test',
277 );
278
279 //returns empty for sites without .htaccess, or if all headers are already in use
280 $recommended_headers = RSSSL()->admin->get_recommended_security_headers();
281 if ( ! empty( $recommended_headers ) ) {
282 $style = '<style>.rsssl-sec-headers-list li {list-style-type:disc;margin-left:20px;}</style>';
283 $list = '<ul class="rsssl-sec-headers-list"><li>' . implode( '</li><li>', $recommended_headers ) . '</li></ul>';
284 $result['status'] = 'recommended';
285 $result['label'] = __( 'Not all essential security headers are installed', 'really-simple-ssl' );
286 $result['description'] = sprintf( '<p>%s</p>', __( 'Your website does not send all essential security headers.', 'really-simple-ssl' ) . $style . $list );
287 $result['actions'] = sprintf(
288 '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s</a></p>',
289 rsssl_link('site-health-recommended-security-headers/'),
290 __( 'Read more', 'really-simple-ssl' )
291 );
292 }
293
294 return $result;
295 }
296
297 /**
298 * Some basic SSL health checks
299 * @return array
300 */
301 public function ssl_tests() {
302 $url = rsssl_admin_url();
303
304 $result = array(
305 'label' => __( '301 SSL redirect enabled', 'really-simple-ssl' ),
306 'status' => 'good',
307 'badge' => array(
308 'label' => __( 'Security' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
309 'color' => 'blue',
310 ),
311 'description' => sprintf(
312 '<p>%s</p>',
313 __( 'You have set a 301 redirect to SSL. This is important for SEO purposes', 'really-simple-ssl' )
314 ),
315 'actions' => '',
316 'test' => 'rsssl_ssl_health',
317 );
318
319 if ( ! rsssl_get_option( 'ssl_enabled' ) ) {
320 if ( rsssl_get_option( 'site_has_ssl' ) ) {
321 $result['status'] = 'recommended';
322 $result['label'] = __( 'SSL is not enabled.', 'really-simple-ssl' );
323 $result['description'] = sprintf(
324 '<p>%s</p>',
325 __(
326 'Really Simple Security detected an SSL certificate, but has not been configured to enforce SSL.',
327 'really-simple-ssl'
328 )
329 );
330 $result['actions'] .= sprintf(
331 '<p><a href="%s">%s</a></p>',
332 $url,
333 __( 'Activate SSL', 'really-simple-ssl' )
334 );
335 } else {
336 $result['status'] = 'recommended';
337 $result['label'] = __( 'No SSL detected', 'really-simple-ssl' );
338 $result['description'] = sprintf(
339 '<p>%s</p>',
340 __( 'Really Simple Security is installed, but no valid SSL certificate is detected.', 'really-simple-ssl' )
341 );
342 }
343 } else {
344 if ( ! RSSSL()->admin->has_301_redirect() ) {
345 $result['status'] = 'recommended';
346 $result['label'] = __( 'No 301 redirect to SSL enabled.', 'really-simple-ssl' );
347 $result['description'] = sprintf(
348 '<p>%s</p>',
349 __( 'To ensure all traffic passes through SSL, please enable a 301 redirect.', 'really-simple-ssl' )
350 );
351 $result['actions'] .= sprintf(
352 '<p><a href="%s">%s</a></p>',
353 $url,
354 __( 'Enable 301 redirect', 'really-simple-ssl' )
355 );
356 } elseif ( RSSSL()->server->uses_htaccess() && rsssl_get_option( 'redirect' ) !== 'htaccess' ) {
357 $result['status'] = 'recommended';
358 $result['label'] = __( '301 .htaccess redirect is not enabled.', 'really-simple-ssl' );
359 $result['description'] = sprintf(
360 '<p>%s</p>',
361 __( 'The 301 .htaccess redirect is the fastest and most reliable redirect option.', 'really-simple-ssl' )
362 );
363 $result['actions'] .= sprintf(
364 '<p><a href="%s">%s</a></p>',
365 $url,
366 __( 'Enable 301 .htaccess redirect', 'really-simple-ssl' )
367 );
368 }
369 }
370 return $result;
371 }
372 }
373 }
374