Problem/Motivation

https://api.drupal.org/api/drupal/includes!common.inc/function/drupal_at...

Attribute values are sanitized by running them through check_plain(). Attribute names are not automatically sanitized. When using user-supplied attribute names, it is strongly recommended to allow only white-listed names, since certain attributes carry security risks and can be abused.

Does not mention that URLs need to be run through filter_xss_bad_protocol() first.

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Template%...

Collects, sanitizes, and renders HTML attributes.

The attribute keys and values are automatically sanitized for output with Html::escape() and the entire attribute string is marked safe for output.

The only place that mentions this is:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Util...

https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_...

Both functions give the impression that they successfully santize attribute values, when they don't if what is going to be sanitized is going to end up in an href, src etc.

Proposed resolution

Add documentation to Attribute in 8.x, then drupal_attributes() in 6.x/7.x that you need to strip dangerous protocols from URLs before passing them in.

Remaining tasks

User interface changes

API changes

Data model changes

Comments

catch created an issue. See original summary.

xjm’s picture

mr.baileys’s picture

Assigned: Unassigned » mr.baileys

DrupalCon Extended Sprints.

stefan.r’s picture

In #2565895: Add a new :placeholder to SafeMarkup::format() for URLs that handles bad protocols we also mention on* and style attributes - could be worth repeating here

pwolanin’s picture

Component: base system » documentation
Category: Task » Bug report
mr.baileys’s picture

Assigned: mr.baileys » Unassigned
Status: Active » Needs review
StatusFileSize
new1.17 KB

drupal_attributes() has been removed in D8, so the attached patch only adds documentation for the Attribute class.

stefan.r’s picture

1. s/an URI/a URI/
2. Should we also rewrite the immediately preceding paragraph in case someone reads that without reading the addition in this patch, I feel like it still hints at safeness a bit too much

mr.baileys’s picture

Thanks for the feedback, I merged both paragraphs into one (since they both concern security), and replaced "sanitize" with "escape" in the first part (since sanitization implies completely safe, which is not the case for URIs that require protocol filtering).

mr.baileys’s picture

Previous patch file was incomplete.

The last submitted patch, 8: 2567741-8-attribute-protocol-filtering-doc.patch, failed testing.

The last submitted patch, 8: 2567741-8-attribute-protocol-filtering-doc.patch, failed testing.

stefan.r’s picture

Looks great :)

pwolanin’s picture

Status: Needs review » Needs work

"the entire attribute string is marked safe for output" is not actually true. The object itself implements SafeStringInterface, so it will not be escaped by Twig.

David_Rothstein’s picture

No
+ * protocol filtering is applied, so when using user-entered input as a value
+ * for a URI attribute (href, src, ...), UrlHelper::stripDangerousProtocols()
+ * should be used to ensure dangerous protocols (such as 'javascript:') are
+ * removed.

As in the other issue, I'm still a little iffy on having the advice in the documentation contradict what Drupal actually does itself in Xss::attributes() (apply protocol-filtering to all attributes, except "title", "alt", and "data-*").

On the other hand, we know that's more conservative than it needs to be and in practice telling people to manually run UrlHelper::stripDangerousProtocols() on almost every attribute is overkill, so I guess it's OK but is there a way we can be more specific here about how you know when you really really need to run it? Like a reference somewhere to what we mean by "URI attribute"? (Not necessarily a blocker for this issue though - documenting it as above is already leaps and bounds better than not documenting it at all.)

mr.baileys’s picture

Status: Needs work » Needs review
StatusFileSize
new1.35 KB

Slightly reworded after talking to @pwolanin.

@David_Rothstein: I changed it to read "No protocol filtering is applied, so when using user-entered input as a value for an attribute that expects an URI (href, src, ...)," ... which might be clearer? I don't think it's feasable to give an exhaustive list here like the on at http://stackoverflow.com/questions/2725156/complete-list-of-html-tag-att...

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

Like a reference somewhere to what we mean by "URI attribute"

As far as HTML5 is concerned, likely every attribute listed in http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1 that has the word URL in it. But I'd be a bit wary of explicitly mentioning them all here, we only really know that href works. In another issue it could be interesting to do the protocol filtering in Attribute itself, based on this list of attributes...

What I don't see is any attributes that might be a URL, or might not be a URL, it's usually pretty clear. So marking RTBC, David_Rothstein if you object feel free to set back to NR.

  • catch committed d271293 on 8.0.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...
catch’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Looks great to me. Committed/pushed to 8.0.x, thanks!

Moving to 7.x for backport.

David_Rothstein’s picture

The final version looks good to me too (though it should say "a URI" rather than "an URI").

Maybe in the backport we should add similar documentation to format_string() here too, since the new placeholder added in #2565895: Add a new :placeholder to SafeMarkup::format() for URLs that handles bad protocols may not make sense to backport (it could be done, but we couldn't actually use it consistently in core without breaking lots of translations).

catch’s picture

Yes I"d definitely add to format_string() and possibly t() itself in 7.x

  • catch committed d271293 on 8.1.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...
sivaji_ganesh_jojodae’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new1.17 KB

Patch ported to D7 (not sure if I'm correct).

Status: Needs review » Needs work

The last submitted patch, 22: 2567741_22.patch, failed testing.

jhodgdon’s picture

This looks pretty good to me... Part of it is a bit confusing though.

The first sentence in this paragraph starts with "Attribute values...". So far, so good. Then the next one starts in about the attribute names. Then the third sentence, about "No protocol filtering" is about the values again. Then the fourth is about the names again.

Can we rearrange this so that the parts about the values are together, and the parts about the names are together? This would make much more sense. Thanks!

  • catch committed d271293 on 8.3.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...

  • catch committed d271293 on 8.3.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...

  • catch committed d271293 on 8.4.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...

  • catch committed d271293 on 8.4.x
    Issue #2567741 by mr.baileys: Attribute/drupal_attributes() docs do not...

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.