Problem/Motivation
Drupal is secure by default. Developers should opt out of security not opt in. The new https://drupal.org/node/2067859 page title default to pass through violates this maxim.
And I must add, I waited long enough after raising this in private for something to happen but it doesn't: in general Drupal 8 totally dropped the ball on this. It's astonishing and insanely worrisome that intentionally (it made it into the change notice) such a change was a) conceived b) reviewed and c) committed. One of the fundamental strengths of Drupal is the security. I have found several fundamental weaknesses this year without running a bit of code just by reading docs or code. What are you guys doing, hm?
Also, the change notice
public function getTitle() {
return 'Foo: ' . \Drupal::config()->get('system.site')->get('name');
}
this is missing translation and is an XSS hole. Oh and a fatal error cos it should be config('system.site')
but what's a fatal between friends. What are you guys doing? (no it's not that the config() syntax changed since the change notice was written, I checked.)
I have looked for a _title_callback
in core , found the theme settings page and added the recommended return \Drupal::config('system.site')->get('name');
code to ThemeHandler::getName
for a quick test. The results are attached. It's not a pretty picture.
Also this just gets better and better every freakin' minute wherever I look, cos this particular callback is defined as theme_handler:getName
which uses a service ID aaaaaaand that's not in the change notice.
Proposed resolution
Note the page title is fixed by twig autoescape.
Remaining tasks
Do something with breadcrumbs.
User interface changes
None.
API changes
Comment | File | Size | Author |
---|---|---|---|
#39 | breadcrumb-xss-2264041-39.patch | 2.67 KB | dawehner |
#35 | 2264041-35.patch | 1.8 KB | cilefen |
#26 | 2264041_26.patch | 1.81 KB | chx |
#24 | 2264041-23.patch | 2.16 KB | pwolanin |
#22 | 2264041-22.patch | 1.05 KB | pwolanin |
Comments
Comment #1
dawehnerWould it be okay to move to filter_xss_admin() instead?
Comment #2
chx CreditAttribution: chx commentedWhy not filter_xss($title, array()) then? Or even strip_tags although someone would need to look whether strip_tags is reliable. I can't readily see what html tags are even valid in title.
Comment #3
chx CreditAttribution: chx commentedComment #4
chx CreditAttribution: chx commentedComment #5
benjy CreditAttribution: benjy commentedI had a quick look at this and adding the below in hook_preprocess_page() goes straight to the page.
Since this is the recommended way now drupal_set_title() has gone, I think a strip_tags by default would be preferred somewhere?
Unfortunately I'm not sure where it would go, drupal_prepare_page() is too early for preprocess functions and DefaultHtmlFragmentRenderer::render() doesn't feel right either.
Comment #6
chx CreditAttribution: chx commentedFixing #5 is beyond what I proposed; even D7 fails short there; although I would be madly in love with anyone who fixed that :D
Consider template_preprocess_html doing
strip_tags($page->getTitle())
and template_preprocess_html NOT doing any of that:$variables['title'] = $variables['page']['#title'];
this would be a good place to add a strip tags or a filter_xss with a very few tags allowed or hell even filter_xss_admin if that's what I can get but doing nothing is unacceptable.Stopping template processes blowing XSS holes, I think, we are talking of a security hardening and not a fundamentally broken subsystem as we have it now.
Comment #7
benjy CreditAttribution: benjy commentedI could be wrong but my thinking was that the change notice indicates that in D7 it was like:
So when people are converting their modules to D8, they'd come along and change it to
And they'd inadvertently introduce a possible security issue.
Comment #8
chx CreditAttribution: chx commentedWhere does the change notice suggest adding anything like that to preprocess? I can not find $var , process , a mention of theme or anything like that. If it does suggest so then it must nuked from orbit and fast before someone thinks that's a good idea.
Comment #9
benjy CreditAttribution: benjy commentedI've seen contrib modules doing stuff like that when overriding the title, for example: http://drupalcode.org/project/h1_title_override.git/blob/HEAD:/h1_title_...
The change notice doesn't specifically mention preprocess but I wouldn't have thought that would stop some people attempting it this way when they're trying to override one off node/page titles.
I'd like to see title to be run through a strip tags, seems like a sensible default to me.
Comment #10
chx CreditAttribution: chx commentedWe could do in template_process_page and amend the change notice telling people not to mess with the title in process_page. That hardening is backportable, even.
Comment #11
dawehnerSo maybe this?
Comment #12
chx CreditAttribution: chx commentedI do not think this is the right place ; however my solution is not working 'cos process is removed (even if the doxygen for it is not). Great. Someone who knows what's going in D8 needs to find a place after preprocess but before templating.
Comment #13
dawehnerWell, we can also do that directly in the template.
Comment #14
chx CreditAttribution: chx commentedThe process removal change notice points to this https://drupal.org/node/2052023 change notice about RenderWrapper.
Comment #15
pwolanin CreditAttribution: pwolanin commentedtrying to trace through the flow in D7 (omg) I this it is always check_plain() by default, though there is the option to bypass.
I'm not clear why the patch in #11 would resolve the problem of an unsafe #title?
Comment #16
chx CreditAttribution: chx commentedComment #17
chx CreditAttribution: chx commentedComment #18
chx CreditAttribution: chx commentedComment #19
chx CreditAttribution: chx commentedThere isn't a lot to review in that patch, TBH.
Comment #20
chx CreditAttribution: chx commentedComment #21
pwolanin CreditAttribution: pwolanin commentedSo, in this issue Tim argued that the return of the title resolver (and hence the title callback) is expected be safe and we added documentation that effect to the title resolver: #2267763: Page titles with %placeholders are broken when used as breadcrumbs
However, re-reading the arguments here I am now thinking that's not viable given the example here. Can we put the xss filter into the title resolver?
Comment #22
pwolanin CreditAttribution: pwolanin commentedActually - I take that back. the comment added to that interface is right - it's the title resolver implementation that's missing the step of sanitizing the title that comes from the title callback.
Comment #23
chx CreditAttribution: chx commentedGood start but won't cover XSS in preprocess. You need to a RenderWrapper call postpone the ripping to the very last minute. (process_page in d7 was doing drupal_get_title and drupal_set_title was check_plain'ing)
Comment #24
pwolanin CreditAttribution: pwolanin commentedSo, this should catch more, but doesn't really help with preprocess. Maybe we need to save the original title and filter it again if it changed?
Comment #25
chx CreditAttribution: chx commentedIf you need to do this twice then it's living proof that the whole system is fundamentally unsecure. That should not never, ever be necessary (as it is not in D7). I can repeat #23 if you want: template_preprocess_page must do something (and perhaps template_preprocess_html should too) that causes a stripping to run after every preprocess. My understanding of D8 is very limited so I can only repeat what I read in the change notice: the mechanism for this is RenderWrapper.
Comment #26
chx CreditAttribution: chx commentedWe can do , for example , this. Alternatively we can do all sorts of twig wizardry: new functions, building a new mountain of twig nodes w/e.
Comment #27
pwolanin CreditAttribution: pwolanin commented@chx - ok, though we are then twice filtering anything that comes out of the title resolver.
Comment #28
pwolanin CreditAttribution: pwolanin commentedIt feels like a good part of the problem here is that in 7 we had the parameter for drupal_set_title() to we could know when to pass-through the value but it was sanitized by default.
If PHP had support for "tainted" strings this might be an easier problem to solve. Ot possible with TWIG auto-escape if that's enabled.
In the mean time, perhaps the title resolver or other case that wasn't a string passed though could wrap it in a simple object instance (possibly with just __toString()) and we can then treat all non-object titles as tainted and needing to be sanitized?
Comment #29
pwolanin CreditAttribution: pwolanin commentedI don't see that Drupal 7 actually protects against an unsafe value being set during the page preprocess step. I see this as the process step:
So we are only getting a safe value if nothing was set by a theme or module before.
however, dawehner points out that most code would use drupal_set_title() rather than setting the variable, so it was easy to do the right thing.
Comment #30
chx CreditAttribution: chx commented#1825952: Turn on twig autoescape by default makes short work of what my patch attempts clumsily to do. The breadcrumb is a different story since HTML TRUE.
Comment #31
pwolanin CreditAttribution: pwolanin commentedchx - yes, though we'd need to figure out how to not double-escape titles such as those already run through t() with placeholders
I think my patch in #24 at least addresses the current breadcumb hole and others from custom titles. Do you want me to pull that into a different issue? add a test?
Comment #32
chx CreditAttribution: chx commentedAdd a test please and repurpose this for the breadcrumb fix as that is not doable by autoescape. As for double escape; the whole issue and patch is about avoiding double escaping.
Comment #33
chx CreditAttribution: chx commentedComment #34
dawehnerFor breadcrumbs I filled #2314599: Use title/url instead of l() for building breadcrumb
Comment #35
cilefen CreditAttribution: cilefen commentedReroll.
Comment #37
dawehner@chx
Is still issue actually still needed? Just curious.
Comment #38
chx CreditAttribution: chx commentedAs in #32: is there a test for XSS'd breadcrumbs? #2314599: Use title/url instead of l() for building breadcrumb doesn't seem to contain a test...
Comment #39
dawehnerHere is one. Not sure whether it is a bug that in case you hard-code the HTML inside the routing system, you can put everything in there. This is basically the same problem as t('
'), which we consider as safe in a lot of places.Comment #40
Fabianx CreditAttribution: Fabianx commentedRTBC, as the route is not user supplied data, this should be fine.
Thanks for the test.
Comment #41
alexpottCommitted 4300214 and pushed to 8.0.x. Thanks!