Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
\Drupal\Core\Render\Element\HtmlTag::preRenderConditionalComments() calls SafeMarkup::set() which is meant to be for internal use only.
Proposed resolution
- Remove the call by using SafeString::create() instead so that the list of safe strings isn't polluted with a fragment
Remaining tasks
Review patch
Manual testing steps
Do these steps both with HEAD and with the patch applied:
- Install Drupal 8.
- Review the HTML of the page in the
<head>
area, between the<link>
and<script>
blocks. Look for the conditional comment that begins with<!--[if lte IE 8]>
. - Compare the output above in HEAD and with the patch applied. Confirm that the HTML is identical.
For testing of the prefix/suffix:
Add $element['#prefix'] = '<blink>test&</blink>'
and $element['#suffix'] = '<blink>test&</blink>'
and verify that the result before and after are the same.
Add $element['#prefix'] = SafeString::create('<blink>test&</blink>')
and $element['#suffix'] = SafeString::create('<blink>test&</blink>')
and verify that the result before and after are the same.
User interface changes
N/A
API changes
N/A
Comment | File | Size | Author |
---|---|---|---|
#25 | interdiff-2544262-20-25.txt | 921 bytes | josephdpurcell |
#25 | 2544262-25.patch | 2.81 KB | josephdpurcell |
#20 | 2544262-20.patch | 2.74 KB | stefan.r |
#20 | interdiff-18-20.txt | 718 bytes | stefan.r |
#18 | 2544262-18.patch | 2.47 KB | stefan.r |
Comments
Comment #1
akalata CreditAttribution: akalata as a volunteer commentedComment #2
akalata CreditAttribution: akalata as a volunteer commentedComment #3
akalata CreditAttribution: akalata as a volunteer commentedComment #4
YesCT CreditAttribution: YesCT commentedso I relooked up the difference between set and format to remind myself why this is one of the acceptable ways of removing set.
And format sanatizes the values for the placeholders first, and then marks the string as safe.
The patch stays in scope.
so manual testing this... doesn't include a value for $prefix (and $suffix). So I'm not 100% confident that we are manually testing the escaping of some of this.
this bit is IR specific, ... do we want to require manual testing in IE?
... I can't remember the tag for manual testing in IE.
Comment #5
akalata CreditAttribution: akalata as a volunteer commented4.1: The prefix and suffix are already being passed through
Xss::filterAdmin
, so we can pass those through SafeMarkup::format without worrying about them. However, if we wanted to strictly conform to the usage of SafeMarkup::format() maybe we should use ! instead of @ as the first character of the $args key?Comment #6
YesCT CreditAttribution: YesCT commentedso, the strings we are concatenating, are first being run though Xss::filterAdmin() and my initial worry was that we might be marking the parts of the string safe, and then the whole concatenated string safe, and polluting the list of safe strings with fragments.
but, checking the docs on filterAdmin():
this is not marking the fragments safe, and seems to be exactly the recommended use case of filterAdmin().
I think @ is still the thing to use with filter... and looked to #2501683: Remove SafeMarkup::set in _update_message_text() and it seems to use @ in format even with strings we are assuming are safe.
----
so, doing a code review, this looks great.
but we might still need some manual testing steps for the prefix and suffix and for IE.
Comment #7
akalata CreditAttribution: akalata as a volunteer commentedI'm having trouble figuring out where this code is being called, in order to specifically test the
$elements['#prefix']
and$elements['#suffix']
pieces that are being checked before SafeMarkup::format() is called:core.libraries.yml
, but adding 'prefix' and 'suffix' keys at the same level as the 'browsers' key had no effectAre we sure that the prefix and suffix are being used for preRenderConditionalComments?
Comment #8
YesCT CreditAttribution: YesCT commentedneeds work to add tests for the prefix and suffix that comes from the element array
Comment #9
Wim LeersShouldn't this use
SafeString::create()
?To find reviewers: look at the
git blame
view for this file. I'd say general theme system maintainers are also good candidates to look at this.Comment #10
stefan.r CreditAttribution: stefan.r commentedSeems the prefix and suffix already have test coverage through
HtmlTagTest::testPreRenderConditionalComments()
:)@akalata the #prefix/#suffix is actually not being used in core, but for manual testing, we can add the following code in JsCollectionRenderer::render() when it loops through the JS assets:
This may as well use
SafeString::create()
, patch attached.Comment #14
stefan.r CreditAttribution: stefan.r commentedComment #16
stefan.r CreditAttribution: stefan.r commentedComment #18
stefan.r CreditAttribution: stefan.r commentedComment #19
joelpittetThis looks like a decent change to make, especially for performance.
Although in either case we need to know that we've done our homework.
So variables involved $expression, $prefix, $suffix, need to be documented as to why they are 'safe' (aka have they been escaped/filtered/etc previously?) and why the resulting string is also safe.
This needs work for documentation but I believe the direction should be good to go. #2 didn't need this extra documentation because it escaped thorugh
@
Comment #20
stefan.r CreditAttribution: stefan.r commentedThe documentation was actually already there, just not visible in the patch.. it just still referred to
SafeMarkup::set()
.Looking at the complete actual function it's clear that everything has been at least admin-escaped: $expression is either IE, !IE or the safe value of
$element['#browsers']
, and$prefix
/$suffix
are the safe values of$element['#prefix']
/$element['#suffix']
themselves.Comment #21
josephdpurcell CreditAttribution: josephdpurcell commentedFrom manual testing I see before:
And after applying 2544262-20.patch I see:
So, these are exactly the same as expected.
Then, after modifying
Drupal\Core\Asset\JsCollectionRenderer:render
to be:I see before:
And after:
Which is expected.
And after changing it to:
I see before:
And after I see:
Which I expect.
I also confirmed that all calls to
SafeMarkup::set()
are removed from the\Drupal\Core\Render\Element\HtmlTag::preRenderConditionalComments()
method.I reviewed the documentation on why
SafeString::create()
is still there and believe it is clear that $expression, $prefix, and $suffix are safe.I believe it to meet the requirements of #2280965: [meta] Remove every SafeMarkup::set() call. Setting to RTBC.
Comment #22
YesCT CreditAttribution: YesCT commentedfor people reviewing this, note #2525908: HtmlTag render element's prefix and suffix can be marked safe when they are not changed elements to element.
Comment #23
josephdpurcell CreditAttribution: josephdpurcell commentedComment #24
joelpittetIt's not "admin escaped" but "admin XSS filtered" and could maybe be massaged a bit more explicit to explain why the entire string is safe.
Also a note on the manual testing, since we changed from
SafeMarkup::format()
toSafeString::create()
there should be no difference in the output and that test would really not test this specific issue but whetherSafeString::create()
==SafeMarkup::set()
which very much should be the case (except for maybe passing in batch where the big list gets lost). Although good to test probably doesn't have much extra to say about this patch.Comment #25
josephdpurcell CreditAttribution: josephdpurcell commentedUpdated the comment according to #24.
Comment #26
YesCT CreditAttribution: YesCT commentedthat interdiff looks like what was asked for. and #21 reviewed all the things. :) rtbc.
Comment #27
alexpottThis IS nice. :) SafeString is good to use here because we definitely are internal to the render system and
$prefix
and$suffix
have been admin filtered above if they are not marked safe.Committed 7c4205a and pushed to 8.0.x. Thanks!