Make WordPress Core

Changeset 50072


Ignore:
Timestamp:
01/29/2021 07:09:49 PM (4 years ago)
Author:
flixos90
Message:

Security, Site Health: Improve accuracy in messaging about HTTPS support.

Following up on [49904], this changeset focuses mainly on improving the guidance about the current state of HTTPS in Site Health.

  • Correct the existing copy to indicate that both the Site Address and the WordPress Address need to be changed to fully switch to HTTPS.
  • Link to the respective input fields via anchor links rather than to the overall General Settings screen.
  • Show different copy if the site is using HTTPS for the WordPress Address (for example to have only the administration panel in HTTPS), but not for the Site Address.
  • Inform the user about potential problems even when the site is already using HTTPS, for example if the SSL certificate was no longer valid.
  • Always rely on fresh information for determining HTTPS support issues in Site Health, and therefore change the https_status test to become asynchronous.
  • Rename the new private wp_is_owned_html_output() function to a more appropriate wp_is_local_html_output().

Props adamsilverstein, flixos90, johnjamesjacoby, timothyblynjacobs.
See #47577.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-site-health.php

    r50041 r50072  
    109109            // Don't run https test on development environments.
    110110            if ( $this->is_development_environment() ) {
    111                 unset( $tests['direct']['https_status'] );
     111                unset( $tests['async']['https_status'] );
    112112            }
    113113
     
    14991499     */
    15001500    public function get_test_https_status() {
     1501        // Enforce fresh HTTPS detection results. This is normally invoked by using cron, but for Site Health it should
     1502        // always rely on the latest results.
     1503        wp_update_https_detection_errors();
     1504
    15011505        $result = array(
    15021506            'label'       => __( 'Your website is using an active HTTPS connection' ),
     
    15221526
    15231527        if ( ! wp_is_using_https() ) {
     1528            // If the website is not using HTTPS, provide more information about whether it is supported and how it can
     1529            // be enabled.
    15241530            $result['status'] = 'critical';
    15251531            $result['label']  = __( 'Your website does not use HTTPS' );
    15261532
    1527             if ( is_ssl() ) {
    1528                 $result['description'] = sprintf(
    1529                     '<p>%s</p>',
    1530                     sprintf(
    1531                         /* translators: %s: URL to General Settings screen. */
    1532                         __( 'You are accessing this website using HTTPS, but your <a href="%s">WordPress Address</a> is not set up to use HTTPS by default.' ),
    1533                         esc_url( admin_url( 'options-general.php' ) )
    1534                     )
    1535                 );
     1533            if ( wp_is_site_url_using_https() ) {
     1534                if ( is_ssl() ) {
     1535                    $result['description'] = sprintf(
     1536                        '<p>%s</p>',
     1537                        sprintf(
     1538                            /* translators: %s: URL to Settings > General > Site Address. */
     1539                            __( 'You are accessing this website using HTTPS, but your <a href="%s">Site Address</a> is not set up to use HTTPS by default.' ),
     1540                            esc_url( admin_url( 'options-general.php' ) . '#home' )
     1541                        )
     1542                    );
     1543                } else {
     1544                    $result['description'] = sprintf(
     1545                        '<p>%s</p>',
     1546                        sprintf(
     1547                            /* translators: %s: URL to Settings > General > Site Address. */
     1548                            __( 'Your <a href="%s">Site Address</a> is not set up to use HTTPS.' ),
     1549                            esc_url( admin_url( 'options-general.php' ) . '#home' )
     1550                        )
     1551                    );
     1552                }
    15361553            } else {
    1537                 $result['description'] = sprintf(
    1538                     '<p>%s</p>',
    1539                     sprintf(
    1540                         /* translators: %s: URL to General Settings screen. */
    1541                         __( 'Your <a href="%s">WordPress Address</a> is not set up to use HTTPS.' ),
    1542                         esc_url( admin_url( 'options-general.php' ) )
    1543                     )
    1544                 );
     1554                if ( is_ssl() ) {
     1555                    $result['description'] = sprintf(
     1556                        '<p>%s</p>',
     1557                        sprintf(
     1558                            /* translators: 1: URL to Settings > General > WordPress Address, 2: URL to Settings > General > Site Address. */
     1559                            __( 'You are accessing this website using HTTPS, but your <a href="%1$s">WordPress Address</a> and <a href="%2$s">Site Address</a> are not set up to use HTTPS by default.' ),
     1560                            esc_url( admin_url( 'options-general.php' ) . '#siteurl' ),
     1561                            esc_url( admin_url( 'options-general.php' ) . '#home' )
     1562                        )
     1563                    );
     1564                } else {
     1565                    $result['description'] = sprintf(
     1566                        '<p>%s</p>',
     1567                        sprintf(
     1568                            /* translators: 1: URL to Settings > General > WordPress Address, 2: URL to Settings > General > Site Address. */
     1569                            __( 'Your <a href="%1$s">WordPress Address</a> and <a href="%2$s">Site Address</a> are not set up to use HTTPS.' ),
     1570                            esc_url( admin_url( 'options-general.php' ) . '#siteurl' ),
     1571                            esc_url( admin_url( 'options-general.php' ) . '#home' )
     1572                        )
     1573                    );
     1574                }
    15451575            }
    15461576
     
    15621592                );
    15631593            }
     1594        } elseif ( ! wp_is_https_supported() ) {
     1595            // If the website is using HTTPS, but HTTPS is actually not supported, inform the user about the potential
     1596            // problems.
     1597            $result['status'] = 'critical';
     1598            $result['label']  = __( 'There are problems with the HTTPS connection of your website' );
     1599
     1600            $https_detection_errors = get_option( 'https_detection_errors' );
     1601            if ( ! empty( $https_detection_errors['ssl_verification_failed'] ) ) {
     1602                $result['description'] = sprintf(
     1603                    '<p>%s</p>',
     1604                    sprintf(
     1605                        /* translators: %s: URL to Settings > General > WordPress Address. */
     1606                        __( 'Your <a href="%s">WordPress Address</a> is set up to use HTTPS, but the SSL certificate appears to be invalid.' ),
     1607                        esc_url( admin_url( 'options-general.php' ) . '#siteurl' )
     1608                    )
     1609                );
     1610            } else {
     1611                $result['description'] = sprintf(
     1612                    '<p>%s</p>',
     1613                    sprintf(
     1614                        /* translators: %s: URL to Settings > General > WordPress Address. */
     1615                        __( 'Your <a href="%s">WordPress Address</a> is set up to use HTTPS, but your website appears to be unavailable when using an HTTPS connection.' ),
     1616                        esc_url( admin_url( 'options-general.php' ) . '#siteurl' )
     1617                    )
     1618                );
     1619            }
     1620            $result['description'] .= sprintf(
     1621                '<p>%s</p>',
     1622                __( 'Talk to your web host about resolving this HTTPS issue for your website.' )
     1623            );
    15641624        }
    15651625
     
    22012261                    'test'  => 'utf8mb4_support',
    22022262                ),
    2203                 'https_status'              => array(
    2204                     'label' => __( 'HTTPS status' ),
    2205                     'test'  => 'https_status',
    2206                 ),
    22072263                'ssl_support'               => array(
    22082264                    'label' => __( 'Secure communication' ),
     
    22482304                    'has_rest'          => true,
    22492305                    'async_direct_test' => array( WP_Site_Health::get_instance(), 'get_test_loopback_requests' ),
     2306                ),
     2307                'https_status'         => array(
     2308                    'label'             => __( 'HTTPS status' ),
     2309                    'test'              => rest_url( 'wp-site-health/v1/tests/https-status' ),
     2310                    'has_rest'          => true,
     2311                    'async_direct_test' => array( WP_Site_Health::get_instance(), 'get_test_https_status' ),
    22502312                ),
    22512313                'authorization_header' => array(
     
    26152677        // Don't run https test on development environments.
    26162678        if ( $this->is_development_environment() ) {
    2617             unset( $tests['direct']['https_status'] );
     2679            unset( $tests['async']['https_status'] );
    26182680        }
    26192681
  • trunk/src/wp-includes/https-detection.php

    r49909 r50072  
    1010 * Checks whether the website is using HTTPS.
    1111 *
    12  * This is based on whether the home and site URL are using HTTPS.
    13  *
    14  * @since 5.7.0
     12 * This is based on whether both the home and site URL are using HTTPS.
     13 *
     14 * @since 5.7.0
     15 * @see wp_is_home_url_using_https()
     16 * @see wp_is_site_url_using_https()
    1517 *
    1618 * @return bool True if using HTTPS, false otherwise.
    1719 */
    1820function wp_is_using_https() {
    19     if ( 'https' !== wp_parse_url( home_url(), PHP_URL_SCHEME ) ) {
     21    if ( ! wp_is_home_url_using_https() ) {
    2022        return false;
    2123    }
    2224
     25    return wp_is_site_url_using_https();
     26}
     27
     28/**
     29 * Checks whether the current site URL is using HTTPS.
     30 *
     31 * @since 5.7.0
     32 * @see home_url()
     33 *
     34 * @return bool True if using HTTPS, false otherwise.
     35 */
     36function wp_is_home_url_using_https() {
     37    return 'https' === wp_parse_url( home_url(), PHP_URL_SCHEME );
     38}
     39
     40/**
     41 * Checks whether the current site's URL where WordPress is stored is using HTTPS.
     42 *
     43 * This checks the URL where WordPress application files (e.g. wp-blog-header.php or the wp-admin/ folder) are
     44 * accessible.
     45 *
     46 * @since 5.7.0
     47 * @see site_url()
     48 *
     49 * @return bool True if using HTTPS, false otherwise.
     50 */
     51function wp_is_site_url_using_https() {
    2352    // Use direct option access for 'siteurl' and manually run the 'site_url'
    24     // filter because site_url() will adjust the scheme based on what the
     53    // filter because `site_url()` will adjust the scheme based on what the
    2554    // current request is using.
    2655    /** This filter is documented in wp-includes/link-template.php */
    2756    $site_url = apply_filters( 'site_url', get_option( 'siteurl' ), '', null, null );
    2857
    29     if ( 'https' !== wp_parse_url( $site_url, PHP_URL_SCHEME ) ) {
    30         return false;
    31     }
    32 
    33     return true;
     58    return 'https' === wp_parse_url( $site_url, PHP_URL_SCHEME );
    3459}
    3560
     
    105130        if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
    106131            $support_errors->add( 'bad_response_code', wp_remote_retrieve_response_message( $response ) );
    107         } elseif ( false === wp_is_owned_html_output( wp_remote_retrieve_body( $response ) ) ) {
     132        } elseif ( false === wp_is_local_html_output( wp_remote_retrieve_body( $response ) ) ) {
    108133            $support_errors->add( 'bad_response_source', __( 'It looks like the response did not come from this site.' ) );
    109134        }
     
    160185 * @return bool|null True/false for whether HTML was generated by this site, null if unable to determine.
    161186 */
    162 function wp_is_owned_html_output( $html ) {
     187function wp_is_local_html_output( $html ) {
    163188    // 1. Check if HTML includes the site's Really Simple Discovery link.
    164189    if ( has_action( 'wp_head', 'rsd_link' ) ) {
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php

    r49716 r50072  
    8080                    'permission_callback' => function () {
    8181                        return $this->validate_request_permission( 'loopback_requests' );
     82                    },
     83                ),
     84                'schema' => array( $this, 'get_public_item_schema' ),
     85            )
     86        );
     87
     88        register_rest_route(
     89            $this->namespace,
     90            sprintf(
     91                '/%s/%s',
     92                $this->rest_base,
     93                'https-status'
     94            ),
     95            array(
     96                array(
     97                    'methods'             => 'GET',
     98                    'callback'            => array( $this, 'test_https_status' ),
     99                    'permission_callback' => function () {
     100                        return $this->validate_request_permission( 'https_status' );
    82101                    },
    83102                ),
     
    198217        $this->load_admin_textdomain();
    199218        return $this->site_health->get_test_loopback_requests();
     219    }
     220
     221    /**
     222     * Checks that the site's frontend can be accessed over HTTPS.
     223     *
     224     * @since 5.7.0
     225     *
     226     * @return array
     227     */
     228    public function test_https_status() {
     229        $this->load_admin_textdomain();
     230        return $this->site_health->get_test_https_status();
    200231    }
    201232
  • trunk/tests/phpunit/tests/https-detection.php

    r49904 r50072  
    142142     * @ticket 47577
    143143     */
    144     public function test_wp_is_owned_html_output_via_rsd_link() {
     144    public function test_wp_is_local_html_output_via_rsd_link() {
    145145        // HTML includes RSD link.
    146146        $head_tag = get_echo( 'rsd_link' );
    147147        $html     = $this->get_sample_html_string( $head_tag );
    148         $this->assertTrue( wp_is_owned_html_output( $html ) );
     148        $this->assertTrue( wp_is_local_html_output( $html ) );
    149149
    150150        // HTML includes modified RSD link but same URL.
    151151        $head_tag = str_replace( ' />', '>', get_echo( 'rsd_link' ) );
    152152        $html     = $this->get_sample_html_string( $head_tag );
    153         $this->assertTrue( wp_is_owned_html_output( $html ) );
     153        $this->assertTrue( wp_is_local_html_output( $html ) );
    154154
    155155        // HTML does not include RSD link.
    156156        $html = $this->get_sample_html_string();
    157         $this->assertFalse( wp_is_owned_html_output( $html ) );
    158     }
    159 
    160     /**
    161      * @ticket 47577
    162      */
    163     public function test_wp_is_owned_html_output_via_wlwmanifest_link() {
     157        $this->assertFalse( wp_is_local_html_output( $html ) );
     158    }
     159
     160    /**
     161     * @ticket 47577
     162     */
     163    public function test_wp_is_local_html_output_via_wlwmanifest_link() {
    164164        remove_action( 'wp_head', 'rsd_link' );
    165165
     
    167167        $head_tag = get_echo( 'wlwmanifest_link' );
    168168        $html     = $this->get_sample_html_string( $head_tag );
    169         $this->assertTrue( wp_is_owned_html_output( $html ) );
     169        $this->assertTrue( wp_is_local_html_output( $html ) );
    170170
    171171        // HTML includes modified WLW manifest link but same URL.
    172172        $head_tag = str_replace( ' />', '>', get_echo( 'wlwmanifest_link' ) );
    173173        $html     = $this->get_sample_html_string( $head_tag );
    174         $this->assertTrue( wp_is_owned_html_output( $html ) );
     174        $this->assertTrue( wp_is_local_html_output( $html ) );
    175175
    176176        // HTML includes WLW manifest link with alternative URL scheme.
     
    178178        $head_tag = false !== strpos( $head_tag, 'https://' ) ? str_replace( 'https://', 'http://', $head_tag ) : str_replace( 'http://', 'https://', $head_tag );
    179179        $html     = $this->get_sample_html_string( $head_tag );
    180         $this->assertTrue( wp_is_owned_html_output( $html ) );
     180        $this->assertTrue( wp_is_local_html_output( $html ) );
    181181
    182182        // HTML does not include WLW manifest link.
    183183        $html = $this->get_sample_html_string();
    184         $this->assertFalse( wp_is_owned_html_output( $html ) );
    185     }
    186 
    187     /**
    188      * @ticket 47577
    189      */
    190     public function test_wp_is_owned_html_output_via_rest_link() {
     184        $this->assertFalse( wp_is_local_html_output( $html ) );
     185    }
     186
     187    /**
     188     * @ticket 47577
     189     */
     190    public function test_wp_is_local_html_output_via_rest_link() {
    191191        remove_action( 'wp_head', 'rsd_link' );
    192192        remove_action( 'wp_head', 'wlwmanifest_link' );
     
    195195        $head_tag = get_echo( 'rest_output_link_wp_head' );
    196196        $html     = $this->get_sample_html_string( $head_tag );
    197         $this->assertTrue( wp_is_owned_html_output( $html ) );
     197        $this->assertTrue( wp_is_local_html_output( $html ) );
    198198
    199199        // HTML includes modified REST API link but same URL.
    200200        $head_tag = str_replace( ' />', '>', get_echo( 'rest_output_link_wp_head' ) );
    201201        $html     = $this->get_sample_html_string( $head_tag );
    202         $this->assertTrue( wp_is_owned_html_output( $html ) );
     202        $this->assertTrue( wp_is_local_html_output( $html ) );
    203203
    204204        // HTML includes REST API link with alternative URL scheme.
     
    206206        $head_tag = false !== strpos( $head_tag, 'https://' ) ? str_replace( 'https://', 'http://', $head_tag ) : str_replace( 'http://', 'https://', $head_tag );
    207207        $html     = $this->get_sample_html_string( $head_tag );
    208         $this->assertTrue( wp_is_owned_html_output( $html ) );
     208        $this->assertTrue( wp_is_local_html_output( $html ) );
    209209
    210210        // HTML does not include REST API link.
    211211        $html = $this->get_sample_html_string();
    212         $this->assertFalse( wp_is_owned_html_output( $html ) );
    213     }
    214 
    215     /**
    216      * @ticket 47577
    217      */
    218     public function test_wp_is_owned_html_output_cannot_determine() {
     212        $this->assertFalse( wp_is_local_html_output( $html ) );
     213    }
     214
     215    /**
     216     * @ticket 47577
     217     */
     218    public function test_wp_is_local_html_output_cannot_determine() {
    219219        remove_action( 'wp_head', 'rsd_link' );
    220220        remove_action( 'wp_head', 'wlwmanifest_link' );
     
    223223        // The HTML here doesn't matter because all hooks are removed.
    224224        $html = $this->get_sample_html_string();
    225         $this->assertNull( wp_is_owned_html_output( $html ) );
     225        $this->assertNull( wp_is_local_html_output( $html ) );
    226226    }
    227227
  • trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php

    r50065 r50072  
    138138            '/wp-site-health/v1/tests/background-updates',
    139139            '/wp-site-health/v1/tests/loopback-requests',
     140            '/wp-site-health/v1/tests/https-status',
    140141            '/wp-site-health/v1/tests/dotorg-communication',
    141142            '/wp-site-health/v1/tests/authorization-header',
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r50065 r50072  
    61886188                    {
    61896189                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/tests/loopback-requests"
     6190                    }
     6191                ]
     6192            }
     6193        },
     6194        "/wp-site-health/v1/tests/https-status": {
     6195            "namespace": "wp-site-health/v1",
     6196            "methods": [
     6197                "GET"
     6198            ],
     6199            "endpoints": [
     6200                {
     6201                    "methods": [
     6202                        "GET"
     6203                    ],
     6204                    "args": []
     6205                }
     6206            ],
     6207            "_links": {
     6208                "self": [
     6209                    {
     6210                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/tests/https-status"
    61906211                    }
    61916212                ]
Note: See TracChangeset for help on using the changeset viewer.