Problem/Motivation

We still have ~8 theme functions in core.

Potentially modules doing a minimal port from 7.x-8.x will have them too.

At least one core contributor in a sprint discussion yesterday had either not realized or had forgotten that no autoescaping happens in theme functions.

If they can, so can other people, so we could end up with XSS as people remove early-escape from places then forget it ends up in a theme function.

Non-test remaining theme functions in core:

  • theme_indentation
  • theme_field_ui_table
  • theme_language_negotiation_configure_browser_form_table
  • theme_language_content_settings_table
  • theme_system_modules_details
  • theme_system_modules_uninstall
  • theme_views_view_fields
  • theme_views_view_field

Proposed resolution

1. Document this clearly for theme functions.

2. Add a helper function that theme functions can use to get the same escaping behavior as Twig templates

3. Review existing theme functions in core to double check things depending on the above.

Unfortunately it is not possible to auto-escape $variables for themes without making assumptions we can not make. $variables is not just a flat array for keys and scalar values. The values can be render arrays and objects. We cannot go into the render arrays and escape early as this would break rendering. And we can not change properties of objects cause that is just wrong. See #89. Therefore we need to do it the same way as Twig does it - which is wrap every output into the template with a method. Twig can do this automatically - because it has a compilation step - theme functions can not because, well, they are PHP.

Proposed resolution

Add a helper method to help people that still use theme functions, to escape there output, if its already safe.

Remaining tasks

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#106 interdiff.txt3.04 KBDavid_Rothstein
#106 2572929-106.patch9.8 KBDavid_Rothstein
#102 interdiff.txt676 bytesdawehner
#102 2572929-102.patch9.77 KBdawehner
#97 increment.txt518 bytespwolanin
#97 2572929-95.patch9.76 KBpwolanin
#92 increment.txt3.62 KBpwolanin
#92 2572929-92.patch9.74 KBpwolanin
#86 interdiff.txt2.65 KBdawehner
#86 2572929-86.patch8.8 KBdawehner
#80 interdiff.txt611 bytesdawehner
#80 2572929-80.patch8.74 KBdawehner
#75 theme-2572929-75.patch8.71 KBhussainweb
#75 interdiff-72-75.txt962 byteshussainweb
#72 interdiff.txt911 bytesxjm
#72 theme-2572929-72.patch8.74 KBxjm
#64 2572929-60-61.interdiff.txt772 bytesmikeker
#64 2572929-61.patch8.72 KBmikeker
#61 2572929-55-60.interdiff.txt2.48 KBmikeker
#61 2572929-60.patch8.64 KBmikeker
#55 interdiff-50-54.txt3.52 KBxjm
#55 theme-2572929-54.patch8.64 KBxjm
#50 interdiff.txt2.25 KBdawehner
#50 2572929-50.patch6.52 KBdawehner
#44 interdiff.txt1.11 KBdawehner
#44 2572929-44.patch8.61 KBdawehner
#38 interdiff.txt3.97 KBdawehner
#38 2572929-31.patch5.87 KBdawehner
#25 2572929-23-25.interdiff.txt4.64 KBmikeker
#25 2572929-18-25.interdiff.txt4.35 KBmikeker
#25 2572929-25-theme-escape.patch3.74 KBmikeker
#23 2572929-23.patch4.37 KBstefan.r
#23 interdiff-17-23.txt2.8 KBstefan.r
#18 interdiff.txt2.06 KBdawehner
#18 2572929-17.patch4.83 KBdawehner
#15 increment.txt2.08 KBpwolanin
#15 2572929-14.patch4.25 KBpwolanin
#13 increment.txt1.42 KBpwolanin
#13 257292-13.patch2.95 KBpwolanin
#12 257292-12.patch2.26 KBpwolanin
#8 2572929-7.patch1.4 KBdawehner

Comments

catch created an issue. See original summary.

stefan.r’s picture

What would be the drawback of automatically admin XSS filtering unsafe output? (other than the performance hit and disallowing people from intentionally putting javascript in a theme_* function)

chx’s picture

The way to solve this issue is to list all the remaining theme_ functions and figure out what are they doing and whether they would suffer from an xss filtering. Then possibly whitelist those and throw an exception for any other to stop worrying. Possibly.

dawehner’s picture

Well of course we could deprecate theme functions now, but the question is, is the effort we need to make it secure by default not worth the effort of potential break already ported contrib modules? Maybe its the right thing to break them, as they maybe are unsafe.

From a release management perspective I'd suggest: Apply Xss::filterAdmin, open (probably reopen) the conversions as major and then reevaluate afterwards again if its okay to remove the functionality . On top of Xss::filterAdmin() we should ideally mark the functionality as deprecated already, if possible.

stefan.r’s picture

@dawehner sorry to continue the off-topic discussion, but shouldn't we deprecate them anyway? The question is just whether for Drupal 8.0.0 or 9.0.0.

If for 8, we could just whitelist core theme functions while we try to get rid of them post-8.0.0. Which may break some existing Drupal 8 sites and some ported modules that use theme functions, and make the effort of porting D7 to D8 potentially slightly larger (though it's large anyway compared to D4->D5->D6->D7). But if we do this for 9, I do wonder what people might end up doing in contrib theme functions, and it's yet another (insecure) feature that would have to be supported all throughout the 8.x cycle, as we can't just to deprecate them for a minor release.

Do we have an existing issue about theme function deprecation/removal where we can grep through all of contrib and see how prevalent its use is anyway?

catch’s picture

is the effort we need to make it secure by default not worth the effort of potential break already ported contrib modules? Maybe its the right thing to break them, as they maybe are unsafe.

This is where I'm leading towards, then if you really are doing something that gets broken and you actually need to do, SafeString is there.

Then marking deprecated (in another issue) will discourage people from using them at all, although we have core conversions to get through still of course.

star-szr’s picture

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new1.4 KB

Let's do that! It is secure, it encourages people to do it right. Let's make the deprecation later.

Status: Needs review » Needs work

The last submitted patch, 8: 2572929-7.patch, failed testing.

The last submitted patch, 8: 2572929-7.patch, failed testing.

pwolanin’s picture

Title: Document lack of auto-escape in theme functions and possibly Xss::filterAdmin() the output » Document lack of auto-escape in theme functions and add a theme_autoescape() helper function

Per discussion with @alexpott, changing the title. We need to add something the mimics Twig autoescape for use in theme functions (or even tpl.php files):

see: \Drupal\Core\Template\TwigExtension::escapeFilter()

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +Needs tests
StatusFileSize
new2.26 KB

Here's a start on that as a patch.

Needs tests and the actual doc changes and possibly applying this to any theme fucntion that needs it

pwolanin’s picture

dawehner’s picture

I agree, we want to make people it somehow possible write theme functions in a similar way than twig templates.

pwolanin’s picture

StatusFileSize
new4.25 KB
new2.08 KB

Starting on a test, but it's failing and need to debug.

dawehner’s picture

Looking at that for a while.

star-szr’s picture

Just want to mention this is also relevant for PHPTemplate since it's still hanging out in a dark corner of core.

dawehner’s picture

StatusFileSize
new4.83 KB
new2.06 KB

Usually things work if they are done right.

The last submitted patch, 15: 2572929-14.patch, failed testing.

The last submitted patch, 15: 2572929-14.patch, failed testing.

lauriii’s picture

Status: Needs review » Needs work
  1. +++ b/core/includes/theme.inc
    @@ -358,6 +360,64 @@ function theme_get_setting($setting_name, $theme = NULL) {
    + * Helper function to automatically escape variables in theme functions.
    ...
    +function theme_autoescape($arg) {
    

    I think we could be more explicit what the theme_autoescape actually does because it autoescapes the render array and returns the rendered output.

  2. +++ b/core/includes/theme.inc
    @@ -358,6 +360,64 @@ function theme_get_setting($setting_name, $theme = NULL) {
    +  // @see
    ...
    +    elseif (method_exists($arg, '__toString')) {
    

    @see Drupal\Core\Template\TwigExtension\escapeFilter . This not really DRY so it might be worth moving this into some place where it affects both of the places where this logic occurs.

  3. +++ b/core/includes/theme.inc
    @@ -358,6 +360,64 @@ function theme_get_setting($setting_name, $theme = NULL) {
    +  // This is a normal render array, which is safe by definition, with
    +  // special simple cases already handled.
    

    Nit: special fits the previous line

  4. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -7,7 +7,9 @@
    +use Drupal\Component\Utility\Html;
    ...
    +use Drupal\Core\Render\RenderableInterface;
    

    Unnecessary

  5. +++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeAutoescapeTest.php
    @@ -0,0 +1,58 @@
    +  /**
    +   * Modules to enable.
    +   *
    +   * @var array
    +   */
    +  public static $modules = [];
    

    No empty modules property is needed

  6. +++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeAutoescapeTest.php
    @@ -0,0 +1,58 @@
    +
    +
    

    Nit: Double line change

pwolanin’s picture

So we need to add more test cases and docs to theme()

stefan.r’s picture

Status: Needs work » Needs review
StatusFileSize
new2.8 KB
new4.37 KB
chx’s picture

What about an assert(in_array($theme_function, $core_whitelist)) won't break production but will force developers to nuke 'em.

mikeker’s picture

Any reason we can't do this to address #21.2?

(Sorry, left to eat dinner and found @stefan.r had posted a patch, thus the double interdiff...)

Status: Needs review » Needs work

The last submitted patch, 25: 2572929-25-theme-escape.patch, failed testing.

The last submitted patch, 25: 2572929-25-theme-escape.patch, failed testing.

catch’s picture

@chx we should open a followup issue for that, but for me core needs to be converted first before we start enforcing anything, so no whitelist.

lauriii’s picture

Talked briefly with @dawehner about the solution taken on #25 and I think we both agreed that its not optimal but since we are anyway adding Twig autoescape functionality for legacy system it might make sense to have it the way it is done there.

What are we gonna do to support escaping in PHP templates?

chx’s picture

> @chx we should open a followup issue for that, but for me core needs to be converted first before we start enforcing anything, so no whitelist.

Why. The community had almost three years to convert the massive amounts of templates and theme functions. We got this far. That's amazing. Tough luck we couldn't finish it all. We want to release ASAP not wait on these. Contrib or custom won't face anything even remotely as bad as core. Some of those theme functions have seen no change since 2004-2005. Enforcing them to convert is fine.

> What are we gonna do to support escaping in PHP templates?

May I recommend a big fat serving of nothing? Seriously: just use Twig. It's not in core, not my circus, not my monkeys.

chx’s picture

See the top of #1825952: Turn on twig autoescape by default

> a PHPTemplate engine in contrib is going to have to add back a way to securely format variables

It was never meant to be otherwise.

wim leers’s picture

@dawehner walked me through this, explained the problem, and asked for my opinion.

  1. It is not recommended to use theme functions, you should use templates. But we have to be realistic and still support theme functions. But theme functions don't have auto-escaping. Which is why we need this "do the escaping manually" function that theme functions can use.
  2. I think it should be called theme_escape_and_render(), not theme_autoescape(). IMO the latter is nonsensical, because the fact that you have to call that function in the first place means it's manual, not automatic.
  3. Finally, I think theme_escape_and_render() should not duplicate logic, but instead call the Twig extension's escapeFilter() method. Then we have full symmetry and no duplication: variables for templates and in theme functions then get the exact same treatment. Less to understand, less to maintain.

If we choose to not call the Twig extension's escapeFilter() method from theme_escape_and_render(), then I think it's absolutely required that it very explicitly, very visibly state that the code must be kept in sync with escapeFilter().

lauriii’s picture

> What are we gonna do to support escaping in PHP templates?

May I recommend a big fat serving of nothing? Seriously: just use Twig. It's not in core, not my circus, not my monkeys.

Php template engine is still in Drupal core. See: https://api.drupal.org/api/drupal/core!themes!engines!phptemplate!phptem...

wim leers’s picture

Now I read the entire issue.

#4

Well of course we could deprecate theme functions now, but the question is, is the effort we need to make it secure by default not worth the effort of potential break already ported contrib modules? Maybe its the right thing to break them, as they maybe are unsafe.

+1

In #11, @pwolanin changed the course of the issue significantly after a discussion with @alexpott that isn't recorded on the issue. I think because we need to provide this in the mean time, until we deprecate theme functions altogether? But then will we be able to also deprecate the function we add here? I guess?

#17:

Just want to mention this is also relevant for PHPTemplate since it's still hanging out in a dark corner of core.

:O Where?

#28 + #30:

@chx we should open a followup issue for that, but for me core needs to be converted first before we start enforcing anything, so no whitelist.

Why. The community had almost three years to convert the massive amounts of templates and theme functions. We got this far. That's amazing. Tough luck we couldn't finish it all. We want to release ASAP not wait on these. Contrib or custom won't face anything even remotely as bad as core. Some of those theme functions have seen no change since 2004-2005. Enforcing them to convert is fine.

I like @chx's thinking here. Why can't we do that?

stefan.r’s picture

But we have to be realistic and still support theme functions

@Wim Leers why is this being realistic? They're insecure, and elsewhere in core we "use" plenty of things without "supporting" them by marking them @internal. I don't understand why can't do so for theme functions - just because we might use some legacy theme functions doesnt mean they need to be part of the API.

Can't we somehow move this handful of legacy functions into its own thing so we can add an assert() that doesn't involve whitelisting? Or cripple the

chx’s picture

URGH if phptemplate is still there then nuke it. Kill it with fire. Or move it to contrib. Whatever you do, don't ship with it!!!! URGH. Modules can't ship with phptemplate / .tpl.php files anyways! Thanks god. ThemeManager::render hardwires twig_render_template and .html.twig for modules otherwise ppl would pester contrib maintainers for templates in the engine they use. Urgh nope. I didn't add that but it's really wise. We nuked config.storage.install saying everyone will ship YAML and that be the end of it. Same sane reasoning. Anyways, phptemplate is definitely out of scope and we don't have the time to write a new layer for making phptemplate secure. If that's a doable thing. Just swipe it under the rug and forget about it.

lauriii’s picture

Wouldn't it be enough to write docs that phptemplates don't have autoescaping and shouldn't be used for that reason? Modules can't change templating engine because otherwise themers would be very confused when they would have to create their own templates for their module.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new5.87 KB
new3.97 KB
dawehner’s picture

People: The title of this issue is

Document lack of auto-escape in theme functions

,
PHPTemplate is a different thing: Added a new issue: #2574717: Remove PHPTemplate, and add test coverage for multiple theme engine support

alexpott’s picture

wim leers’s picture

Ideally, we get rid of theme functions. But that's a nice-to-have at this point in the cycle. We can't have auto-escape in theme functions. We shouldn't use theme functions. But theme functions in D7 had to take care of escaping themselves, and if they choose to upgrade to D8 and keep those instead of upgrading to Twig, then they still have to do the escaping manually. The helper function we add here ensures that it is done in a way that is consistent with how Twig does it.

@dawehner and @stefan.r firmly believe it is better to have this be entirely decoupled from Twig rather than calling Twig's escaping logic.

I think the only thing missing, is the actual documentation part. Let's add some documentation to theme.api.php? Do we need a change record?

wim leers’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests
dawehner’s picture

Working on the documentation bit

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new8.61 KB
new1.11 KB

Status: Needs review » Needs work

The last submitted patch, 44: 2572929-44.patch, failed testing.

heddn’s picture

+++ b/core/includes/theme.inc
@@ -358,6 +360,67 @@ function theme_get_setting($setting_name, $theme = NULL) {
+ * This mimics the behavior of the auto-escape fucntionality in Twig.

Nit: spelling of functionality.

xjm’s picture

xjm’s picture

  1. +++ b/core/includes/theme.inc
    @@ -358,6 +360,67 @@ function theme_get_setting($setting_name, $theme = NULL) {
    + * Helper function to automatically escape variables in theme functions.
    

    I think this can just be "Automatically escapes variables for theme functions."

  2. +++ b/core/includes/theme.inc
    @@ -358,6 +360,67 @@ function theme_get_setting($setting_name, $theme = NULL) {
    + * You use this method in theme functions to ensure that the result is safe for
    + * output inside HTML fragments.
    + * This mimics the behavior of the auto-escape fucntionality in Twig.
    

    Minor: spelling, line wrapping, remove the word "You" from the beginning.

  3. +++ b/core/includes/theme.inc
    @@ -358,6 +360,67 @@ function theme_get_setting($setting_name, $theme = NULL) {
    + * @see \Drupal\Core\Template\TwigExtension::escapeFilter()
    + */
    +function theme_escape_and_render($arg) {
    +  if ($arg instanceOf SafeStringInterface) {
    +    return (string) $arg;
    +  }
    +  $return = NULL;
    +
    +  if (is_scalar($arg)) {
    +    $return = (string) $arg;
    +  }
    +  elseif (is_object($arg)) {
    +    if ($arg instanceof RenderableInterface) {
    +      $arg = $arg->toRenderable();
    +    }
    +    elseif (method_exists($arg, '__toString')) {
    +      $return = (string) $arg;
    +    }
    +    // You can't throw exceptions in the magic PHP __toString methods, see
    +    // http://php.net/manual/en/language.oop5.magic.php#object.tostring so
    +    // we also support a toString method.
    +    elseif (method_exists($arg, 'toString')) {
    +      $return = $arg->toString();
    +    }
    +    else {
    +      throw new \Exception(t('Object of type "@class" cannot be printed.', array('@class' => get_class($arg))));
    +    }
    +  }
    +
    +  // We have a string or an object converted to a string: Autoescape it!
    +  if (isset($return)) {
    +    return SafeMarkup::isSafe($return, 'html') ? $return:  Html::escape($return);
    +  }
    +
    +  // This is a normal render array, which is safe by definition, with special
    +  // simple cases already handled.
    +
    +  // Early return if this element was pre-rendered (no need to re-render).
    +  if (isset($arg['#printed']) && $arg['#printed'] == TRUE && isset($arg['#markup']) && strlen($arg['#markup']) > 0) {
    +    return (string) $arg['#markup'];
    +  }
    +  $arg['#printed'] = FALSE;
    +  return (string) \Drupal::service('renderer')->render($arg);
    +}
    +
    

    So I understand the desire not to couple the theme API to Twig, but this looks an awful lot like duplicated code. How do we ensure this and the Twig escape filter don't diverge? Could they both call a method from some other independent component?

    Also, I wonder if we should deprecate this function from the outset, with the goal of removing the need for this BC layer in 9.0.x? Or maybe that's part of a separate issue to discuss if we want to deprecate theme functions generally?

  4. +++ b/core/lib/Drupal/Core/Render/theme.api.php
    @@ -86,7 +86,11 @@
    - * theming). In this case, a theme can override the default implementation by
    + * theming). It is important to know that theme functions have to escape
    + * variables. In order to do that properly we provide the helper function
    + * theme_escape_and_render(), which deals with render arrays, safe strings and
    + * similar to the way how twig autoescaping works.
    + * In this case, a theme can override the default implementation by
    

    I think we can probably make this a little more concise e.g. removing the words "It is important to know that" or starting a new paragraph. I'll apply the patch and see if I can suggest an improvement in context; just making a note for now.

  5. +++ b/core/themes/engines/phptemplate/phptemplate.engine
    @@ -3,6 +3,15 @@
    + * Note: The PHP template engine is highly problematic, because each individual
    + * template needs to take care of escaping for each variable manually, so using
    + * it, makes it really hard to provide safe output. Instead its highly
    + * encouraged to use the twig template engine instead.
    + *
    + * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
    + *   The phptemplate engine is deprecated and replaced with the twig template
    + *   engine.
    

    This hunk should probably go in #2574717: Remove PHPTemplate, and add test coverage for multiple theme engine support.

  6. +++ b/core/themes/engines/phptemplate/phptemplate.engine
    @@ -11,6 +20,7 @@
    +  trigger_error('The php template engine is deprecated and should no longer be used. Use the twig template engine instead.', E_USER_DEPRECATED);
    

    I think this hunk needs discussion but is in scope for #2574717: Remove PHPTemplate, and add test coverage for multiple theme engine support in any case rather than this issue.

dawehner’s picture

Assigned: Unassigned » dawehner

Working on it

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new6.52 KB
new2.25 KB

5 and 6 was accidental.

This is an incremental interdiff due to people throwing us out here.

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

looks great

xjm’s picture

Assigned: dawehner » xjm
Status: Reviewed & tested by the community » Needs work

We are still finishing off a few things in the patch; see above reviews. :)

I created a followup that we can reference for the code duplication: #2575065: Refactor theme_escape_and_render() and TwigExtension::escapeFilter() to share reused code

I'll update the patch some more.

xjm’s picture

Title: Document lack of auto-escape in theme functions and add a theme_autoescape() helper function » Document lack of auto-escape in theme functions and add a theme autoescape helper function

The last submitted patch, 44: 2572929-44.patch, failed testing.

xjm’s picture

Assigned: xjm » Unassigned
Status: Needs work » Needs review
StatusFileSize
new8.64 KB
new3.52 KB
+++ b/core/modules/language/language.admin.inc
@@ -201,5 +201,5 @@ function template_preprocess_language_content_settings_table(&$variables) {
-  return '<h4>' . $variables['build']['#title'] . '</h4>' . drupal_render($variables['build']);
+  return '<h4>' . theme_escape_and_render($variables['build']['#title']) . '</h4>' . drupal_render($variables['build']);

Is this hunk just one that we already discovered was unsafe? Do we need to check the rest in a subsequent issue? Ideally of course we would complete the children of #2348381: [META-0 theme functions left] Convert/refactor core theme functions instead.

I added back the accidentally removed docs in theme.api.php and tweaked them a bit. I thought it was important to mention the need for escaping both times theme functions were mentioned, but these doc updates could probably use a double-check.

xjm’s picture

+++ b/core/lib/Drupal/Core/Render/theme.api.php
@@ -70,7 +70,10 @@
+ * templates will autescape variables, theme functions must explicitly escape

Typo: "autescape"

lauriii’s picture

Status: Needs review » Reviewed & tested by the community

One nit which can be fixed on commit:

+++ b/core/lib/Drupal/Core/Render/theme.api.php
@@ -70,7 +70,10 @@
+ * templates will autescape variables, theme functions must explicitly escape

s/autescape/auto-escape

mikeker’s picture

Assigned: Unassigned » mikeker
Status: Reviewed & tested by the community » Needs work
+++ b/core/includes/theme.inc
@@ -358,6 +360,74 @@ function theme_get_setting($setting_name, $theme = NULL) {
+ * Automatically escapes variables for theme functions.

I believe we should avoid the use of "auto" anything for this function as it's not automatically doing it. I'll post a patch updating the docs shortly.

Can someone explain why the approach in #25 was dismissed? From #29

Talked briefly with @dawehner about the solution taken on #25 and I think we both agreed that its not optimal but since we are anyway adding Twig autoescape functionality for legacy system it might make sense to have it the way it is done there.

And #32.3

Finally, I think theme_escape_and_render() should not duplicate logic, but instead call the Twig extension's escapeFilter() method.

Then in #41

@dawehner and @stefan.r firmly believe it is better to have this be entirely decoupled from Twig rather than calling Twig's escaping logic.

I believe a lot of these conversations happened on IRC or in-person at the Barcelona sprint. Can someone give those of us following along at home the gist of it? Thanks!

mikeker’s picture

+++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeAutoescapeTest.php
@@ -0,0 +1,85 @@
+ * Tests the TranslatableString class.
+ *
+ * @group StringTranslation

Copy/paste leftovers?

The last submitted patch, 55: theme-2572929-54.patch, failed testing.

mikeker’s picture

Assigned: mikeker » Unassigned
Status: Needs work » Needs review
StatusFileSize
new8.64 KB
new2.48 KB

Addresses points raised in #56/#57 and #59 along with a few doc cleanups that jumped out at me.

Hopefully these are the final nits to be picked!

Status: Needs review » Needs work

The last submitted patch, 61: 2572929-60.patch, failed testing.

The last submitted patch, 61: 2572929-60.patch, failed testing.

mikeker’s picture

Status: Needs work » Needs review
StatusFileSize
new8.72 KB
new772 bytes

Dang it...

Status: Needs review » Needs work

The last submitted patch, 64: 2572929-61.patch, failed testing.

The last submitted patch, 64: 2572929-61.patch, failed testing.

mikeker queued 64: 2572929-61.patch for re-testing.

The last submitted patch, 64: 2572929-61.patch, failed testing.

xjm’s picture

Fatal error: Uncaught exception 'ReflectionException' with message 'Class Drupal\KernelTests\Core\Theme\ThemeAutoescapeTest does not exist' in /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/simpletest/src/TestDiscovery.php:306
xjm’s picture

Aside from fixing the test, this looks good to me too.

+++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeAutoescapeTest.php
@@ -14,11 +14,11 @@
+ * Tests the theme_escape_and_render function.

Could be fixed on commit: function name needs parens.

Also, just so it's documented here, @mikeker and I chatted a bit about #58. I suggested it was primarily for code decoupling, and that we can improve it in #2575065: Refactor theme_escape_and_render() and TwigExtension::escapeFilter() to share reused code.

xjm’s picture

+++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeAutoescapeTest.php
@@ -0,0 +1,87 @@
+ * Contains \Drupal\KernelTests\Core\Theme\ThemeAutoescapeTest.

Oh, in addition to renaming the file, we should also fix this too. :)

xjm’s picture

Status: Needs work » Needs review
StatusFileSize
new8.74 KB
new911 bytes

Fixing those things.

xjm’s picture

Oh, my question in #55 is still outstanding. Do we have any potential XSS vulnerabilities in core theme functions other than that function? Doesn't need to block this issue, but it's probably important to do.

I'd even suggest documenting on every theme function in core TBH. But especially an inline comment in the ones that actually need the escaping function, since people will copy them to do stuff.

dawehner’s picture

Oh, my question in #55 is still outstanding. Do we have any potential XSS vulnerabilities in core theme functions other than that function? Doesn't need to block this issue, but it's probably important to do.

I haven't checked other theme functions, but this one seemed just too obvious.

+++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeEscapeAndRenderTest.php
@@ -2,7 +2,7 @@
  * @file
- * Contains \Drupal\KernelTests\Core\Theme\ThemeAutoescapeTest.
+ * Contains \Drupal\KernelTests\Core\Theme\ThemeEscapeAndRenderTest.
  */

Good catch!

hussainweb’s picture

StatusFileSize
new962 bytes
new8.71 KB

I made this change first in #2574717: Remove PHPTemplate, and add test coverage for multiple theme engine support and later found out that this is that actual patch where the function is being introduced. I am repeating the same change here.

pwolanin’s picture

Can we have the new function in one place not both? or mark this issue duplicate and closed?

dawehner’s picture

@peter don't make it harder than it is, seriously.

hussainweb’s picture

@pwolanin: I guess the idea is to keep the issues of documenting the escape and adding a helper separate from removing phptemplate from core (so that there's a git history). I imagine this issue must go in first, after which the patch in the other issue would have to be rerolled.

dawehner’s picture

- if (isset($arg['#printed']) && $arg['#printed'] == TRUE && isset($arg['#markup']) && strlen($arg['#markup']) > 0) {
+ if (!empty($arg['#printed']) && isset($arg['#markup']) && strlen($arg['#markup']) > 0) {

... Note: This is coming directly from twig, so we should NOT change here.

dawehner’s picture

StatusFileSize
new8.74 KB
new611 bytes

Reverted that particular thing back, given that it should be more in parallel.

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

Looks great

lauriii’s picture

RTBC++

David_Rothstein’s picture

I think theme_escape_and_render() is a confusing name, because it doesn't always escape. Also, we know we want to recommend its use outside of theme functions too (see #2528284: Document that alternate Drupal 8 theme engines must implement auto-escape or they are not secure and #2574717: Remove PHPTemplate, and add test coverage for multiple theme engine support)... although I suppose "theme" in the function name can mean "theme system" as much as "theme functions"....

I suggest calling it either render_safe() or theme_render_safe().

David_Rothstein’s picture

Or render_safe_html()/theme_render_safe_html() (because someone will point out that it's not safe in all contexts)...

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

It does not always render() either. Setting to needs work to address #83/#84.

Wrt to render context i think it was worth documenting that this is for the HTML context - not sure if it worth encoding that in the name since the 99% use-case of theme functions is to generate HTML.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new8.8 KB
new2.65 KB

We discussed this for a while here. We want to ensure that this is sort of part of the theme system (so its still usable in theme engines)
but discourage people to use it anywhere else, like in random controllers.

larowlan’s picture

+++ b/core/modules/language/language.admin.inc
@@ -201,5 +201,5 @@ function template_preprocess_language_content_settings_table(&$variables) {
 function theme_language_content_settings_table($variables) {
...
+  return '<h4>' . theme_escape_and_render($variables['build']['#title']) . '</h4>' . drupal_render($variables['build']);

I think this is asking for trouble - can't the theme system/engine do this for us - i.e. it already knows which theme hooks are functions and which use a template - can't it call theme_escape_and_render on non templates automatically? We don't want to leave it to chance - it will be easy to forget.

catch’s picture

@larowlan that would be similar to the earlier idea here of Xss::filterAdmin() on the results of theme functions. I still like that idea but others were less keen.

alexpott’s picture

I looked into auto-escaping in the ThemeManager...

    // Generate the output using either a function or a template.
    $output = '';
    if (isset($info['function'])) {
      if (function_exists($info['function'])) {
        // Theme functions do not render via the theme engine, so the output is
        // not autoescaped. However, we can only presume that the theme function
        // has been written correctly and that the markup is safe.
        $output = SafeString::create($info['function']($variables));
      }
    }

Unfortunately this is not possible - since we often just reach into $variables and get whatever we like. In @larowlan's example above, we render $variables['build'] and then reach in and get $variables['build']['#title'].

alexpott’s picture

Status: Needs review » Needs work
+++ b/core/includes/theme.inc
@@ -373,7 +373,8 @@ function theme_get_setting($setting_name, $theme = NULL) {
+ *   The rendered string. This result is not safe in case you use it inside
+ *   an HTML attribute.

We can make this more explicit. The rendered string, safe for use in HTML. The string is not safe when used as an HTML attribute.

I like the new name.

pwolanin’s picture

ok, I'm going to update this now

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new9.74 KB
new3.62 KB

doc fix plus test fixes to avoid unhelpful exception on test fail plus adding descriptive keys and more test cases in the data provider.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

This is lovely!

stefan.r’s picture

s/The string is not safe when used as an HTML attribute./The string is not safe when used inside an HTML attribute./

xjm’s picture

Issue summary: View changes
dawehner’s picture

Do we need a CR for this particular issue?

pwolanin’s picture

StatusFileSize
new9.76 KB
new518 bytes

text fix

@dawehner - do we need a CR for api additions usually?

wim leers’s picture

@dawehner - do we need a CR for api additions usually?

It's important that theme_*() functions use this. So I'd say "yes" in this case.

alexpott’s picture

Issue summary: View changes

Improving the comment about why it is impossible to do this prior to calling the theme function.

xjm’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

Yep, agreed on the CR.

dawehner’s picture

/me works on a CR

dawehner--

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new9.77 KB
new676 bytes

Added https://www.drupal.org/node/2575445, adapted https://www.drupal.org/node/2296163 a bit and realized that we can now leverage the new function

While talking with @xjm on IRC we realized that we can actually do better and not call drupal_render() directly.

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

great. CR looks good.

cilefen’s picture

Issue tags: -Needs change record
David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work

The patch is still referencing the old "theme_escape_and_render" function name in several places.

Wrt to render context i think it was worth documenting that this is for the HTML context - not sure if it worth encoding that in the name since the 99% use-case of theme functions is to generate HTML.

I was thinking more that it is not safe for use in HTML attributes (which is now documented in the patch). I guess it's hard to really communicate that in a function name, but that's what I was aiming for. I'm not sure "autoescape" is the right name here, but it's definitely better than "escape" and it's better documented now also.

David_Rothstein’s picture

Status: Needs work » Needs review
StatusFileSize
new9.8 KB
new3.04 KB

Fixed the outdated references.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Ship it.

alexpott’s picture

Title: Document lack of auto-escape in theme functions and add a theme autoescape helper function » Document lack of auto-escape in theme functions and add a theme autoescape helper function
Status: Reviewed & tested by the community » Fixed

This is a necessary API addition to make it possible to have theme_* functions that are compatible with Twig autoescaping. Basically we have to do what Twig does manually and as show in #89 we can't do anything automatic.

Committed 03ac04f and pushed to 8.0.x. Thanks!

  • alexpott committed 03ac04f on 8.0.x
    Issue #2572929 by dawehner, pwolanin, mikeker, xjm, stefan.r,...

Status: Fixed » Needs work

The last submitted patch, 106: 2572929-106.patch, failed testing.

dawehner’s picture

Status: Needs work » Fixed

Oh testbot

xjm’s picture

We can address some of the related documentation work in #2575551: Document the Drupal 8 sanitization API in the API docs and on Drupal.org. I published the CR.

Did anyone file a followup for checking the other 7 core theme functions?

stefan.r’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.