Make WordPress Core

Ticket #45067: 45067.5.diff

File 45067.5.diff, 6.7 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..5e474fa5aa 100644
    function kses_init() { 
    16871687 * @return string            Filtered string of CSS rules.
    16881688 */
    16891689function safecss_filter_attr( $css, $deprecated = '' ) {
    1690         if ( !empty( $deprecated ) )
     1690        if ( ! empty( $deprecated ) )
    16911691                _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
    16921692
    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 '';
     1693        $css = wp_kses_no_null( $css );
     1694        $css = str_replace( array( "\n", "\r", "\t" ), '', $css );
     1695        $allowed_protocols = wp_allowed_protocols();
    16981696
    16991697        $css_array = explode( ';', trim( $css ) );
    17001698
    function safecss_filter_attr( $css, $deprecated = '' ) { 
    17101708        $allowed_attr = apply_filters( 'safe_style_css', array(
    17111709                'background',
    17121710                'background-color',
     1711                'background-image',
    17131712
    17141713                'border',
    17151714                'border-width',
    function safecss_filter_attr( $css, $deprecated = '' ) { 
    17781777                'list-style-type',
    17791778        ) );
    17801779
    1781         if ( empty($allowed_attr) )
     1780
     1781        /*
     1782         * CSS attributes that accept URL data types.
     1783         *
     1784         * This is in accordance to the CSS spec and unrelated to
     1785         * the sub-set of supported attributes above.
     1786         *
     1787         * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url
     1788         */
     1789        $css_url_data_types = array(
     1790                'background',
     1791                'background-image',
     1792
     1793                'cursor',
     1794
     1795                'list-style',
     1796                'list-style-image',
     1797        );
     1798
     1799        if ( empty( $allowed_attr ) ) {
    17821800                return $css;
     1801        }
    17831802
    17841803        $css = '';
    17851804        foreach ( $css_array as $css_item ) {
    1786                 if ( $css_item == '' )
     1805                if ( $css_item == '' ) {
    17871806                        continue;
    1788                 $css_item = trim( $css_item );
    1789                 $found = false;
     1807                }
     1808
     1809                $css_item        = trim( $css_item );
     1810                $css_test_string = $css_item;
     1811                $found           = false;
     1812                $url_attr        = false;
     1813
    17901814                if ( strpos( $css_item, ':' ) === false ) {
    17911815                        $found = true;
    17921816                } else {
    1793                         $parts = explode( ':', $css_item );
    1794                         if ( in_array( trim( $parts[0] ), $allowed_attr ) )
     1817                        $parts = explode( ':', $css_item, 2 );
     1818                        $css_selector = trim( $parts[0] );
     1819
     1820                        if ( in_array( $css_selector, $allowed_attr, true ) ) {
    17951821                                $found = true;
     1822                                $url_attr = in_array( $css_selector, $css_url_data_types, true );
     1823                        }
     1824                }
     1825
     1826                if ( $found && $url_attr ) {
     1827                        // Simplified: matches the sequence `url(*)`.
     1828                        preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches );
     1829
     1830                        foreach ( $url_matches[0] as $url_match ) {
     1831                                // Clean up the URL from each of the matches above.
     1832                                preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces );
     1833                                $url = trim( $url_pieces[2] );
     1834
     1835                                if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) {
     1836                                        $found = false;
     1837                                        break;
     1838                                } else {
     1839                                        // Remove the whole `url(*)` bit that was matched above from the CSS.
     1840                                        $css_test_string = str_replace( $url_match, '', $css_test_string );
     1841                                }
     1842                        }
    17961843                }
    1797                 if ( $found ) {
    1798                         if( $css != '' )
     1844
     1845                if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) {
     1846                        if ( $css != '' ) {
    17991847                                $css .= ';';
     1848                        }
     1849
    18001850                        $css .= $css_item;
    18011851                }
    18021852        }
  • 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}