[wp-trac] [WordPress Trac] #43215: Allow wp_kses to pass allowed CSS properties
WordPress Trac
noreply at wordpress.org
Fri Feb 2 12:31:49 UTC 2018
#43215: Allow wp_kses to pass allowed CSS properties
-----------------------------+-----------------------------
Reporter: mclaurent | Owner:
Type: feature request | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Security | Version: 4.9.2
Severity: normal | Keywords:
Focuses: |
-----------------------------+-----------------------------
`wp_kses` takes arguments for allowed HTML elements, HTML element
attributes, and allowed protocols. It takes all of these directly via the
function argument through a nicely formatted assoc array. On the side
side, attribute values (i.e. "display: block; visibility: hidden;") are
configured via a hook, which means they are changed globally for all
future calls.
Here a sample how the system is behaving currently:
{{{#!php
<?php
$allowed_output_html = array(
'script' => array(),
'noscript' => array(),
'iframe' => array(
'src' => array(),
'width' => array(),
'height' => array(),
'style' => array(),
),
);
$allowed_output_protocol = array(
'https',
'javascript',
);
$google_tag_manager_noscript <<<'ENDSTRING'
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=123"
height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
ENDSTRING;
echo wp_kses( $google_tag_manager_noscript, $allowed_output_html,
$allowed_output_protocol);
// Outputs as it should except for the
style="display:none;visibility:hidden" portion
// <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=123"
height="0" width="0"></iframe></noscript>
}}}
It seems that currently the only way to allow the "style" attribute from
showing is to write a filter for "safe_style_css" to add in the "display"
and "visibility" attributes, however this means that we are globally
altering this behavior, which in other scenarios would allow unexpected
HTML to appear (ie unsafe element properties). Even when removing the
items immediately after executing the code will not work because the
attribute may in the future be consider secure. This then causes an
inconsistent execution.
For example, imagine that if we wanted to make sure the "float" attribute
was allowed in the attribute value. Currently this value is allowed, so us
adding it in won't change the array. However when we're then undoing our
action (ie removing the "float" attribute from the list of allowed
attributes, we are actually removing one that was set as "safe" by
WordPress themselves. It is easy to imaging how this could escalate
further, when plugins blanket whitelist element attributes, then remove
them from the list, then meaning that no attributes are allowed.
Alternatively, in this same example if we removed our filter (with
remove_filter) right after our wp_kses call, it would mean that our
attribute whitelist would apply to all HTML attributes (display,
visibility,...) and not only the one we would want to whitelist (style).
{{{#!php
<?php
// Function to whitelist safe CSS attributes
function my_safe_css_attributes( $array ){
$array[] = 'display';
$array[] = 'visibility';
return $array;
});
// Function to remove our CSS attributes from the whitelist
function my_safe_css_remove_attributes( $array ){
unset $array['display'];
unset $array['visibility'];
return $array;
}
$allowed_output_html = array(
'script' => array(),
'noscript' => array(),
'iframe' => array(
'src' => array(),
'width' => array(),
'height' => array(),
'style' => array(),
),
);
$allowed_output_protocol = array(
'https',
'javascript',
);
$google_tag_manager_noscript <<<'ENDSTRING'
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=123"
height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
ENDSTRING;
// Telling WordPress about safe CSS attributes...
add_filter( 'safe_style_css', 'my_safe_css_attributes' );
echo wp_kses( $google_tag_manager_noscript, $allowed_output_html,
$allowed_output_protocol);
add_filter( 'safe_style_css', 'my_safe_css_remove_attributes' );
// Outputs as it should.
// <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=123"
height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
}}}
I initially expected the allowed_output_html to allow overriding allowed
attribute values from the "style" element in the array, which I thought
would have been a really neat way of overwriting the execution on a one-
time basis.
{{{#!php
<?php
$allowed_output_html = array(
'script' => array(),
'noscript' => array(),
'iframe' => array(
'src' => array(),
'width' => array(),
'height' => array(),
'style' => array(
'display', 'visibility'
),
),
);
// ...
}}}
I think it would make sense to make the function accept this added level
of depth as it allows very flexible configuration of what attributes are
allowed without compromising attribute
--
Ticket URL: <https://core.trac.wordpress.org/ticket/43215>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list