KSES: Add options for restricting tags based upon their attributes.

This change adds two now attribute-related config options to KSES:
- An array of allowed values can be defined for attributes. If the attribute value doesn't fall into the list, the attribute will be removed from the tag.
- Attributes can be marked as required. If a required attribute is not present, KSES will remove all attributes from the tag. As KSES doesn't match opening and closing tags, it's not possible to safely remove the tag itself, the safest fallback is to strip all attributes from the tag, instead.

Included with this change is an implementation of these options, allowing the `<object>` tag to be stored in posts, but only when it has a `type` attribute set to `application/pdf`.

Props pento, swissspidy, peterwilsoncc, dd32, jorbin.
Fixes #54261.


Built from https://develop.svn.wordpress.org/trunk@51963


git-svn-id: http://core.svn.wordpress.org/trunk@51552 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Gary Pendergast 2021-11-01 02:13:56 +00:00
parent bac6e41c85
commit 2c3205bb84
2 changed files with 51 additions and 1 deletions

View File

@ -271,6 +271,13 @@ if ( ! CUSTOM_TAGS ) {
'lang' => true, 'lang' => true,
'xml:lang' => true, 'xml:lang' => true,
), ),
'object' => array(
'data' => true,
'type' => array(
'required' => true,
'values' => array( 'application/pdf' ),
),
),
'p' => array( 'p' => array(
'align' => true, 'align' => true,
'dir' => true, 'dir' => true,
@ -1165,15 +1172,47 @@ function wp_kses_attr( $element, $attr, $allowed_html, $allowed_protocols ) {
// Split it. // Split it.
$attrarr = wp_kses_hair( $attr, $allowed_protocols ); $attrarr = wp_kses_hair( $attr, $allowed_protocols );
// Check if there are attributes that are required.
$required_attrs = array_filter(
$allowed_html[ $element_low ],
function( $required_attr_limits ) {
return isset( $required_attr_limits['required'] ) && true === $required_attr_limits['required'];
}
);
// If a required attribute check fails, we can return nothing for a self-closing tag,
// but for a non-self-closing tag the best option is to return the element with attributes,
// as KSES doesn't handle matching the relevant closing tag.
$stripped_tag = '';
if ( empty( $xhtml_slash ) ) {
$stripped_tag = "<$element>";
}
// Go through $attrarr, and save the allowed attributes for this element // Go through $attrarr, and save the allowed attributes for this element
// in $attr2. // in $attr2.
$attr2 = ''; $attr2 = '';
foreach ( $attrarr as $arreach ) { foreach ( $attrarr as $arreach ) {
// Check if this attribute is required.
$required = isset( $required_attrs[ strtolower( $arreach['name'] ) ] );
if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) { if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) {
$attr2 .= ' ' . $arreach['whole']; $attr2 .= ' ' . $arreach['whole'];
// If this was a required attribute, we can mark it as found.
if ( $required ) {
unset( $required_attrs[ strtolower( $arreach['name'] ) ] );
}
} elseif ( $required ) {
// This attribute was required, but didn't pass the check. The entire tag is not allowed.
return $stripped_tag;
} }
} }
// If some required attributes weren't set, the entire tag is not allowed.
if ( ! empty( $required_attrs ) ) {
return $stripped_tag;
}
// Remove any "<" or ">" characters. // Remove any "<" or ">" characters.
$attr2 = preg_replace( '/[<>]/', '', $attr2 ); $attr2 = preg_replace( '/[<>]/', '', $attr2 );
@ -1600,6 +1639,17 @@ function wp_kses_check_attr_val( $value, $vless, $checkname, $checkvalue ) {
$ok = false; $ok = false;
} }
break; break;
case 'values':
/*
* The values check is used when you want to make sure that the attribute
* has one of the given values.
*/
if ( false === array_search( strtolower( $value ), $checkvalue, true ) ) {
$ok = false;
}
break;
} // End switch. } // End switch.
return $ok; return $ok;

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '5.9-alpha-51962'; $wp_version = '5.9-alpha-51963';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.