Make WordPress Core

Ticket #45067: 45067.3.diff

File 45067.3.diff, 8.4 KB (added by peterwilsoncc, 6 years ago)
  • src/wp-includes/kses.php

    diff --git src/wp-includes/kses.php src/wp-includes/kses.php
    index 0cf4ce14c4..4c6c64bd6c 100644
    function wp_kses_one_attr( $string, $element ) { 
    549549        $allowed_html = wp_kses_allowed_html( 'post' );
    550550        $allowed_protocols = wp_allowed_protocols();
    551551        $string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) );
    552        
     552
    553553        // Preserve leading and trailing whitespace.
    554554        $matches = array();
    555555        preg_match('/^\s*/', $string, $matches);
    function wp_kses_one_attr( $string, $element ) { 
    561561        } else {
    562562                $string = substr( $string, strlen( $lead ), -strlen( $trail ) );
    563563        }
    564        
     564
    565565        // Parse attribute name and value from input.
    566566        $split = preg_split( '/\s*=\s*/', $string, 2 );
    567567        $name = $split[0];
    function wp_kses_one_attr( $string, $element ) { 
    598598                $value = '';
    599599                $vless = 'y';
    600600        }
    601        
     601
    602602        // Sanitize attribute by name.
    603603        wp_kses_attr_check( $name, $value, $string, $vless, $element, $allowed_html );
    604604
    function wp_kses_attr_parse( $element ) { 
    10621062        } else {
    10631063                $xhtml_slash = '';
    10641064        }
    1065        
     1065
    10661066        // Split it
    10671067        $attrarr = wp_kses_hair_parse( $attr );
    10681068        if ( false === $attrarr ) {
    function wp_kses_attr_parse( $element ) { 
    10721072        // Make sure all input is returned by adding front and back matter.
    10731073        array_unshift( $attrarr, $begin . $slash . $elname );
    10741074        array_push( $attrarr, $xhtml_slash . $end );
    1075        
     1075
    10761076        return $attrarr;
    10771077}
    10781078
    function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) { 
    12151215 * @param array  $allowed_protocols Allowed protocols to keep
    12161216 * @return string Filtered content
    12171217 */
    1218 function wp_kses_bad_protocol($string, $allowed_protocols) {
    1219         $string = wp_kses_no_null($string);
     1218function wp_kses_bad_protocol( $string, $allowed_protocols = array() ) {
     1219        if ( empty( $allowed_protocols ) ) {
     1220                $allowed_protocols = wp_allowed_protocols();
     1221        }
     1222
     1223        $string     = wp_kses_no_null( $string );
    12201224        $iterations = 0;
    12211225
    12221226        do {
    function kses_init() { 
    16871691 * @return string            Filtered string of CSS rules.
    16881692 */
    16891693function safecss_filter_attr( $css, $deprecated = '' ) {
    1690         if ( !empty( $deprecated ) )
     1694        if ( ! empty( $deprecated ) )
    16911695                _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
    16921696
    1693         $css = wp_kses_no_null($css);
    1694         $css = str_replace(array("\n","\r","\t"), '', $css);
    1695 
    1696         if ( preg_match( '%[\\\\(&=}]|/\*%', $css ) ) // remove any inline css containing \ ( & } = or comments
    1697                 return '';
     1697        $css = wp_kses_no_null( $css );
     1698        $css = str_replace( array( "\n", "\r", "\t" ), '', $css );
    16981699
    16991700        $css_array = explode( ';', trim( $css ) );
    17001701
    function safecss_filter_attr( $css, $deprecated = '' ) { 
    17101711        $allowed_attr = apply_filters( 'safe_style_css', array(
    17111712                'background',
    17121713                'background-color',
     1714                'background-image',
    17131715
    17141716                'border',
    17151717                'border-width',
    function safecss_filter_attr( $css, $deprecated = '' ) { 
    17781780                'list-style-type',
    17791781        ) );
    17801782
    1781         if ( empty($allowed_attr) )
     1783
     1784        /*
     1785         * CSS attributes that accept URL data types.
     1786         *
     1787         * This is in accordance to the CSS spec and unrelated to
     1788         * the sub-set of supported attributes above.
     1789         *
     1790         * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url
     1791         */
     1792        $css_url_data_types = array(
     1793                'background',
     1794                'background-image',
     1795
     1796                'cursor',
     1797
     1798                'list-style',
     1799                'list-style-image',
     1800        );
     1801
     1802        if ( empty( $allowed_attr ) ) {
    17821803                return $css;
     1804        }
    17831805
    17841806        $css = '';
    17851807        foreach ( $css_array as $css_item ) {
    1786                 if ( $css_item == '' )
     1808                if ( $css_item == '' ) {
    17871809                        continue;
    1788                 $css_item = trim( $css_item );
    1789                 $found = false;
     1810                }
     1811
     1812                $css_item        = trim( $css_item );
     1813                $css_test_string = $css_item;
     1814                $found           = false;
     1815                $url_attr        = false;
     1816
    17901817                if ( strpos( $css_item, ':' ) === false ) {
    17911818                        $found = true;
    17921819                } else {
    1793                         $parts = explode( ':', $css_item );
    1794                         if ( in_array( trim( $parts[0] ), $allowed_attr ) )
     1820                        $parts = explode( ':', $css_item, 2 );
     1821                        $css_selector = trim( $parts[0] );
     1822
     1823                        if ( in_array( $css_selector, $allowed_attr, true ) ) {
    17951824                                $found = true;
     1825                                $url_attr = in_array( $css_selector, $css_url_data_types, true );
     1826                        }
     1827                }
     1828
     1829                if ( $found && $url_attr ) {
     1830                        // Simplified: matches the sequence `url(*)`.
     1831                        preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches );
     1832
     1833                        foreach ( $url_matches[0] as $url_match ) {
     1834                                // Clean up the URL from each of the matches above.
     1835                                preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces );
     1836                                $url = trim( $url_pieces[2] );
     1837
     1838                                if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url ) ) {
     1839                                        $found = false;
     1840                                        break;
     1841                                } else {
     1842                                        // Remove the whole `url(*)` bit that was matched above from the CSS.
     1843                                        $css_test_string = str_replace( $url_match, '', $css_test_string );
     1844                                }
     1845                        }
    17961846                }
    1797                 if ( $found ) {
    1798                         if( $css != '' )
     1847
     1848                if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) {
     1849                        if ( $css != '' ) {
    17991850                                $css .= ';';
     1851                        }
     1852
    18001853                        $css .= $css_item;
    18011854                }
    18021855        }
  • tests/phpunit/tests/kses.php

    diff --git tests/phpunit/tests/kses.php tests/phpunit/tests/kses.php
    index dea4a881a2..ccb1502f22 100644
    EOF; 
    718718
    719719                $this->assertEquals( "<{$element}>", wp_kses_attr( $element, $attribute, array( 'foo' => false ), array() ) );
    720720        }
     721
     722        /**
     723         * Test URL sanitization in the style tag.
     724         *
     725         * @dataProvider data_kses_style_attr_with_url
     726         *
     727         * @ticket 45067
     728         *
     729         * @param $input string The style attribute saved in the editor.
     730         * @param $expected string The sanitized style attribute.
     731         */
     732        function test_kses_style_attr_with_url( $input, $expected ) {
     733                $actual = safecss_filter_attr( $input );
     734
     735                $this->assertSame( $expected, $actual );
     736        }
     737
     738        /**
     739         * Data provider testing style attribute sanitization.
     740         *
     741         * @return array Nested array of input, expected pairs.
     742         */
     743        function data_kses_style_attr_with_url() {
     744                return array(
     745                        /*
     746                         * Valid use cases.
     747                         */
     748
     749                        // Double quotes.
     750                        array(
     751                                'background-image: url( "http://example.com/valid.gif" );',
     752                                'background-image: url( "http://example.com/valid.gif" )',
     753                        ),
     754
     755                        // Single quotes.
     756                        array(
     757                                "background-image: url( 'http://example.com/valid.gif' );",
     758                                "background-image: url( 'http://example.com/valid.gif' )",
     759                        ),
     760
     761                        // No quotes.
     762                        array(
     763                                'background-image: url( http://example.com/valid.gif );',
     764                                'background-image: url( http://example.com/valid.gif )',
     765                        ),
     766
     767                        // Single quotes, extra spaces.
     768                        array(
     769                                "background-image: url( '  http://example.com/valid.gif ' );",
     770                                "background-image: url( '  http://example.com/valid.gif ' )",
     771                        ),
     772
     773                        // Line breaks, single quotes.
     774                        array(
     775                                "background-image: url(\n'http://example.com/valid.gif' );",
     776                                "background-image: url('http://example.com/valid.gif' )",
     777                        ),
     778
     779                        // Tabs not spaces, single quotes.
     780                        array(
     781                                "background-image: url(\t'http://example.com/valid.gif'\t\t);",
     782                                "background-image: url('http://example.com/valid.gif')",
     783                        ),
     784
     785                        // Single quotes, absolute path.
     786                        array(
     787                                "background: url('/valid.gif');",
     788                                "background: url('/valid.gif')",
     789                        ),
     790
     791                        // Single quotes, relative path.
     792                        array(
     793                                "background: url('../wp-content/uploads/2018/10/valid.gif');",
     794                                "background: url('../wp-content/uploads/2018/10/valid.gif')",
     795                        ),
     796
     797                        // Error check: valid property not containing a URL.
     798                        array(
     799                                "background: red",
     800                                "background: red",
     801                        ),
     802
     803                        /*
     804                         * Invalid use cases.
     805                         */
     806
     807                        // Attribute doesn't support URL properties.
     808                        array(
     809                                'color: url( "http://example.com/invalid.gif" );',
     810                                '',
     811                        ),
     812
     813                        // Mismatched quotes.
     814                        array(
     815                                'background-image: url( "http://example.com/valid.gif\' );',
     816                                '',
     817                        ),
     818
     819                        // Bad protocol, double quotes.
     820                        array(
     821                                'background-image: url( "bad://example.com/invalid.gif" );',
     822                                '',
     823                        ),
     824
     825                        // Bad protocol, single quotes.
     826                        array(
     827                                "background-image: url( 'bad://example.com/invalid.gif' );",
     828                                '',
     829                        ),
     830
     831                        // Bad protocol, single quotes.
     832                        array(
     833                                "background-image: url( 'bad://example.com/invalid.gif' );",
     834                                '',
     835                        ),
     836
     837                        // Bad protocol, single quotes, strange spacing.
     838                        array(
     839                                "background-image: url( '  \tbad://example.com/invalid.gif ' );",
     840                                '',
     841                        ),
     842
     843                        // Bad protocol, no quotes.
     844                        array(
     845                                'background-image: url( bad://example.com/invalid.gif );',
     846                                '',
     847                        ),
     848
     849                        // No URL inside url().
     850                        array(
     851                                'background-image: url();',
     852                                '',
     853                        ),
     854                );
     855        }
    721856}