WordPress.org

Make WordPress Core

Changeset 43732


Ignore:
Timestamp:
10/16/2018 04:12:21 AM (12 months ago)
Author:
peterwilsoncc
Message:

Formatting: Add pre-save content filter to make target=_blank always secure.

Props notnownikki, iseulde, azaozz.
Merges [42770] to the 5.0 branch.
Fixes #43187.

Location:
branches/5.0
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/5.0/src/wp-includes/default-filters.php

    r43729 r43732  
    118118    add_filter( $filter, 'balanceTags', 50 );
    119119}
     120
     121// Add proper rel values for links with target.
     122foreach ( array(
     123    'title_save_pre',
     124    'content_save_pre',
     125    'excerpt_save_pre',
     126    'content_filtered_save_pre',
     127    'pre_comment_content',
     128    'pre_term_description',
     129    'pre_link_description',
     130    'pre_link_notes',
     131    'pre_user_description',
     132) as $filter ) {
     133    add_filter( $filter, 'wp_targeted_link_rel' );
     134};
    120135
    121136// Format strings for display.
  • branches/5.0/src/wp-includes/formatting.php

    r43444 r43732  
    27722772    }
    27732773    return "<a $text rel=\"$rel\">";
     2774}
     2775
     2776/**
     2777 * Adds rel noreferrer and noopener to all HTML A elements that have a target.
     2778 *
     2779 * @param string $text Content that may contain HTML A elements.
     2780 * @return string Converted content.
     2781 */
     2782function wp_targeted_link_rel( $text ) {
     2783    // Don't run (more expensive) regex if no links with targets.
     2784    if ( stripos( $text, 'target' ) !== false && stripos( $text, '<a ' ) !== false ) {
     2785        $text = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', 'wp_targeted_link_rel_callback', $text );
     2786    }
     2787
     2788    return $text;
     2789}
     2790
     2791/**
     2792 * Callback to add rel="noreferrer noopener" string to HTML A element.
     2793 *
     2794 * Will not duplicate existing noreferrer and noopener values
     2795 * to prevent from invalidating the HTML.
     2796 *
     2797 * @param array $matches Single Match
     2798 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
     2799 */
     2800function wp_targeted_link_rel_callback( $matches ) {
     2801    $link_html = $matches[1];
     2802    $rel_match = array();
     2803
     2804    /**
     2805     * Filters the rel values that are added to links with `target` attribute.
     2806     *
     2807     * @since 5.0.0
     2808     *
     2809     * @param string The rel values.
     2810     * @param string $link_html The matched content of the link tag including all HTML attributes.
     2811     */
     2812    $rel = apply_filters( 'wp_targeted_link_rel', 'noopener noreferrer', $link_html );
     2813
     2814    // Value with delimiters, spaces around are optional.
     2815    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\\1|i';
     2816    preg_match( $attr_regex, $link_html, $rel_match );
     2817
     2818    if ( empty( $rel_match[0] ) ) {
     2819        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
     2820        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
     2821        preg_match( $attr_regex, $link_html, $rel_match );
     2822    }
     2823
     2824    if ( ! empty( $rel_match[0] ) ) {
     2825        $parts = preg_split( '|\s+|', strtolower( $rel_match[2] ) );
     2826        $parts = array_map( 'esc_attr', $parts );
     2827        $needed = explode( ' ', $rel );
     2828        $parts = array_unique( array_merge( $parts, $needed ) );
     2829        $delimiter = trim( $rel_match[1] ) ? $rel_match[1] : '"';
     2830        $rel = 'rel=' . $delimiter . trim( implode( ' ', $parts ) ) . $delimiter;
     2831        $link_html = str_replace( $rel_match[0], $rel, $link_html );
     2832    } else {
     2833        $link_html .= " rel=\"$rel\"";
     2834    }
     2835
     2836    return "<a $link_html>";
    27742837}
    27752838
  • branches/5.0/tests/phpunit/tests/rest-api/rest-attachments-controller.php

    r43727 r43732  
    940940                    ),
    941941                    'description' => array(
    942                         'raw'      => '<a href="#" target="_blank">link</a>',
    943                         'rendered' => '<p><a href="#" target="_blank">link</a></p>',
     942                        'raw'      => '<a href="#" target="_blank" rel="noopener noreferrer">link</a>',
     943                        'rendered' => '<p><a href="#" target="_blank" rel="noopener noreferrer">link</a></p>',
    944944                    ),
    945945                    'caption' => array(
    946                         'raw'      => '<a href="#" target="_blank">link</a>',
    947                         'rendered' => '<p><a href="#" target="_blank">link</a></p>',
     946                        'raw'      => '<a href="#" target="_blank" rel="noopener noreferrer">link</a>',
     947                        'rendered' => '<p><a href="#" target="_blank" rel="noopener noreferrer">link</a></p>',
    948948                    ),
    949949                )
  • branches/5.0/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r43727 r43732  
    29252925                    ),
    29262926                    'content' => array(
    2927                         'raw'      => '<a href="#" target="_blank">link</a>',
    2928                         'rendered' => '<p><a href="#" target="_blank">link</a></p>',
     2927                        'raw'      => '<a href="#" target="_blank" rel="noopener noreferrer">link</a>',
     2928                        'rendered' => '<p><a href="#" target="_blank" rel="noopener noreferrer">link</a></p>',
    29292929                    ),
    29302930                    'excerpt' => array(
    2931                         'raw'      => '<a href="#" target="_blank">link</a>',
    2932                         'rendered' => '<p><a href="#" target="_blank">link</a></p>',
     2931                        'raw'      => '<a href="#" target="_blank" rel="noopener noreferrer">link</a>',
     2932                        'rendered' => '<p><a href="#" target="_blank" rel="noopener noreferrer">link</a></p>',
    29332933                    ),
    29342934                )
Note: See TracChangeset for help on using the changeset viewer.