Make WordPress Core


Ignore:
Timestamp:
10/12/2023 12:39:18 PM (13 months ago)
Author:
jorbin
Message:

Application Passwords: Prevent the use of some pseudo protocols in application passwords.

Props tykoted, xknown, peterwilsoncc, jorbin, timothyblynjacobs, martinkrcho, paulkevan, dd32, ehtis.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/user.php

    r56599 r56837  
    639639 * @since 5.6.0
    640640 * @since 6.2.0 Allow insecure HTTP connections for the local environment.
     641 * @since 6.3.2 Validates the success and reject URLs to prevent javascript pseudo protocol being executed.
    641642 *
    642643 * @param array   $request {
     
    652653 */
    653654function wp_is_authorize_application_password_request_valid( $request, $user ) {
    654     $error    = new WP_Error();
    655     $is_local = 'local' === wp_get_environment_type();
    656 
    657     if ( ! empty( $request['success_url'] ) ) {
    658         $scheme = wp_parse_url( $request['success_url'], PHP_URL_SCHEME );
    659 
    660         if ( 'http' === $scheme && ! $is_local ) {
     655    $error = new WP_Error();
     656
     657    if ( isset( $request['success_url'] ) ) {
     658        $validated_success_url = wp_is_authorize_application_redirect_url_valid( $request['success_url'] );
     659        if ( is_wp_error( $validated_success_url ) ) {
    661660            $error->add(
    662                 'invalid_redirect_scheme',
    663                 __( 'The success URL must be served over a secure connection.' )
     661                $validated_success_url->get_error_code(),
     662                $validated_success_url->get_error_message()
    664663            );
    665664        }
    666665    }
    667666
    668     if ( ! empty( $request['reject_url'] ) ) {
    669         $scheme = wp_parse_url( $request['reject_url'], PHP_URL_SCHEME );
    670 
    671         if ( 'http' === $scheme && ! $is_local ) {
     667    if ( isset( $request['reject_url'] ) ) {
     668        $validated_reject_url = wp_is_authorize_application_redirect_url_valid( $request['reject_url'] );
     669        if ( is_wp_error( $validated_reject_url ) ) {
    672670            $error->add(
    673                 'invalid_redirect_scheme',
    674                 __( 'The rejection URL must be served over a secure connection.' )
     671                $validated_reject_url->get_error_code(),
     672                $validated_reject_url->get_error_message()
    675673            );
    676674        }
     
    701699    return true;
    702700}
     701
     702/**
     703 * Validates the redirect URL protocol scheme. The protocol can be anything except http and javascript.
     704 *
     705 * @since 6.3.2
     706 *
     707 * @param string $url - The redirect URL to be validated.
     708 *
     709 * @return true|WP_Error True if the redirect URL is valid, a WP_Error object otherwise.
     710 */
     711function wp_is_authorize_application_redirect_url_valid( $url ) {
     712    $bad_protocols = array( 'javascript', 'data' );
     713    if ( empty( $url ) ) {
     714        return true;
     715    }
     716
     717    // Based on https://www.rfc-editor.org/rfc/rfc2396#section-3.1
     718    $valid_scheme_regex = '/^[a-zA-Z][a-zA-Z0-9+.-]*:/';
     719    if ( ! preg_match( $valid_scheme_regex, $url ) ) {
     720        return new WP_Error(
     721            'invalid_redirect_url_format',
     722            __( 'Invalid URL format.' )
     723        );
     724    }
     725
     726    /**
     727     * Filters the list of invalid protocols used in applications redirect URLs.
     728     *
     729     * @since 6.3.2
     730     *
     731     * @param string[]  $bad_protocols Array of invalid protocols.
     732     * @param string    $url The redirect URL to be validated.
     733     */
     734    $invalid_protocols = array_map( 'strtolower', apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ) );
     735
     736    $scheme   = wp_parse_url( $url, PHP_URL_SCHEME );
     737    $host     = wp_parse_url( $url, PHP_URL_HOST );
     738    $is_local = 'local' === wp_get_environment_type();
     739
     740    // validates if the proper URI format is applied to the $url
     741    if ( empty( $host ) || empty( $scheme ) || in_array( strtolower( $scheme ), $invalid_protocols, true ) ) {
     742        return new WP_Error(
     743            'invalid_redirect_url_format',
     744            __( 'Invalid URL format.' )
     745        );
     746    }
     747
     748    if ( 'http' === $scheme && ! $is_local ) {
     749        return new WP_Error(
     750            'invalid_redirect_scheme',
     751            __( 'The URL must be served over a secure connection.' )
     752        );
     753    }
     754
     755    return true;
     756}
Note: See TracChangeset for help on using the changeset viewer.