Problem/Motivation

Opening this as major, but I think it blocks both #2567743: Add protocol filtering to the core Attribute component and #2506479: Replace !placeholder with @placeholder for non URLs in t() in Views, except for t() output that is used as an attribute value, the latter being critical, so we may need to bump it.

Splitting this out of #2567743: Add protocol filtering to the core Attribute component because we agreed the scope of protocol hardening itself is major and I don't think this changes that, it just enables that hardening to happen.

There are two cases where SafeStrings can be used as attributes, both are problematic for opposite reasons.

@ -402,7 +402,7 @@ public function getDisplayDetails($view, $display) {
         if (!$is_enabled) {
           $build['top']['actions']['enable'] = array(
             '#type' => 'submit',
-            '#value' => $this->t('Enable !display_title', array('!display_title' => $display_title)),
+            '#value' => $this->t('Enable @display_title', array('@display_title' => $display_title)),
             '#limit_validation_errors' => array(),
             '#submit' => array('::submitDisplayEnable', '::submitDelayDestination'),
             '#prefix' => '<li class="enable">',

That value gets put into Attributes. While the results of t() are marked as a SafeString, the Attribute class escapes everything it gets, ignoring SafeString altogether.

This results in a double-escaping but in Views, and fixing that blocks the removal of !placeholder

The other case is covered in depth by #2569041: Figure out what to do about attribute filtering in Twig.

A previous issue, #2531824: Attribute class to check safe strings before escaping (has tests), aimed to check SafeStringInterface inside Attribute. However that would open Attribute up to strings that are marked safe because they were Xss::filter()ed regardless of eventual rendering context, and may not actually be safe/correct for an attribute. An example of this would be #2569041-7: Figure out what to do about attribute filtering in Twig. That string would get past Xss::filter() but not Html::escape().

Conceptually, we have three use cases for SafeString/SafeStringInterface but only one interface to describe them.

The current supported use-case is 'A string that is safe for an HTML node/fragment'.
i.e.
Llamas: ain't they great.

Lllamas: ain't they <em>great</em>

Or How to use the &lt;em&gt; HTML tag to make sentences about Llamas more emphatic

Or How to use javascript:alert('XSS') to pwn a site.

These are all 'safe strings'.

Any string run through Xss:filter() or Html::escape() meets this criteria.

A string that is going to be used in any HTML attribute.
Only strings run through Html::escape() (or equivalent) meet this criteria. There's no way to indicate this at the moment.
A string that is going to be used in an HTML href/src or other URI attribute.
Only strings run through Html::escape(UrlHelper::stripDangerousProtocols()) meet this criteria.

Proposed resolution

Add a new interface:

AttributeSafeStringInterface

The Attribute class can then check instanceof AttributeSafeStringInterface before escaping individual attributes values.

Either in this issue, or in #2567743: Add protocol filtering to the core Attribute component add UriAttributeSafeStringInterface, which it could then check before doing protocol filtering when that is added. The need for this where responsive image modules sets data: as an src attribute (which UrlHelper::stripDangerousProtocols() would correctly strip out) is what led me to opening this issue.

Note that this issue partly conflicts with option #1 from #2509218: Ensure that SafeString objects can be used in non-HTML contexts, but I think in a good way, since this is precisely a case of the "!placeholder by another name" situation we want to avoid.

Remaining tasks

User interface changes

Less double escaping.

API changes

Only additions.

Data model changes

CommentFileSizeAuthor
#4 2569485-4.patch8.92 KBpwolanin
#3 2569485-3.patch7.23 KBpwolanin

Comments

catch created an issue. See original summary.

catch’s picture

Note that the last patch on #2567743: Add protocol filtering to the core Attribute component adds the interface and relevant changes to AttributeString, it is nothing complicated but please look at that patch first before posting one here - or I'll try to split it out.

pwolanin’s picture

Status: Active » Needs work
StatusFileSize
new7.23 KB

Here's a rough start on creating interfaces and a class. Not complete, needs tests, etc

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +Needs tests
StatusFileSize
new8.92 KB

A little more complete

catch’s picture

Priority: Major » Normal
Status: Needs review » Postponed

#2576533: Rename SafeStringInterface to MarkupInterface and move related classes is probably a better answer to this problem, especially the EscapedMarkup which given PlainTextOutput we still might want to process for an attribute value. If that gets in I think we can mark this as duplicate.

wim leers’s picture

catch’s picture

Status: Active » Closed (duplicate)

I think this can just be duplicate, marking as such.