Part of meta-issue #1788918: [GTD] [META] Prepare for Twig main engine core inclusion until December 1

Follow-up from: #1696786: Integrate Twig into core: Implementation issue

Motivation

100% of all custom themes are insecure (the rest is rounding error). The reason is often that developers forget to escape their data in the templates.

Problems

  • To use twig autoescape every string that has been escaped already needs to be marked as "safe", so that it does not get escaped twice.
  • Concatenation of a safe string is an unsafe string
  • Different escaping strategies need to be used for different contexts (html, css, js, html attributes)
  • Our implementation of auto-render makes the optimized |raw filter usage not possible

Approaches available

  • a) Have Twig handle security internally and assume every string in $variables is secure (not true for objects). That would keep backwards compatible options to also have node.tpl.php etc. templates secure while still preventing accidental XSS via node.title or db_query in templates.
  • b) Mark things that are secure, as such by utilizing a TypedData SafeString either automatically or manually.

For both variants are two possible implementations: Implicit and Explicit

  • a) 1) Preprocess variables before rendering of template and mark every string as secure, needs only is_object check.
  • => Has some performance overhead, but simple todo.
  • a) 2) Mark strings secure as they are gathered from _context, by overriding getAttribute and getContext and set $this->secure = TRUE in getContext and $this->secure = FALSE in getAttribute if an object is encountered, wrap every encountered String as a Twig_Markup.
  • => Compile time overhead, but little less run time overhead.
  • b) 1) Do it like we do now and have an escaped string remain secure until it is concatenated.
  • => Needs fixing of many tests, change from untyped strings to typed strings.
  • b) 2) Explicitly use drupal_mark_safe(check_plain($node->title)) in the preprocess_ and process_ functions and wherever something is rendered to be output in a template.
  • => Overhead in preprocess, process, etc. functions. They all need to be adjusted. Still needs typed SafeStrings. Developers need to learn to mark strings as safe for output as well as escaping.

Solution

  • Wrap everything that is returned from check_plain, check_markup, etc. in Twig_Markup() objects.
  • Tell Developers to wrap the concatenated escaped strings again in a Twig_Markup to mark it as safe again
  • Document clearly that developers need to take care of security escaping themselves when using inline-css and inline-script with user input (better not do this at all)
  • Fix the raw filter to explicitly return a Twig_Markup object instead of compile time optimizing it away.

Advantages

Limitations

Not solved here are (currently?):

  • Auto-escaping in different contexts (JS, CSS) though it can be done manually via ({% autoescape js/css %}) tags
  • Users putting non-escaped data in #prefix / #suffix or via #theme_wrapper
  • The solution is only as secure if all "marked safe" parts are secure (if all theme_ functions are gone and all goes via twig it is secure)
  • No auto-escape for .tpl.php files and it needs to handle Twig_Markup objects
  • Might need a function like is_twig_string for that

Disadvantages

  • Performance: Obviously wrapping in Twig_Markup and doing __toString has overhead. Lets find out how worse it is.

Original report

Right now, we can't autoescape in twig because we are still calling drupal_render as an interim solution. When drupal_render concatenates it's results it loses the metadata containing the information whether a string is already escaped or not.

We need to replace or rewrite drupal_render so that the escaped strings are stored in a Twig_Markup object instead of being lost when flattened. When this is done we can turn autoescaping back on in twig.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jenlampton’s picture

Important tagging

jenlampton’s picture

Issue tags: +Twig

adding tag

Fabianx’s picture

We will also need to make for example $vars['css'] in header safe by wrapping them as Twig_Markup.

To properly support easy concatenation we could use something like: #1788192: Prepare autosanitization

It might be that we need to extend Twig_Markup as Drupal_Safe_Markup to do some magic things like storing a series of:

Safe|Unsafe|Safe etc.

But this should be discussed here.

Fabianx’s picture

First patch: DONE

We have auto escaping in the twig_engine branch of the sandbox now.

Fabianx’s picture

Title: Replace drupal_render with a twig-based alterntaive that retains metadata about escaping » Twig: Show autoescape mode benefits and risks

Hijacking this issue for now to followup / fork() from main integration issue.

Fabianx’s picture

Issue summary: View changes

Updated issue summary.

Fabianx’s picture

Status: Active » Needs review
Issue tags: +Needs tests, +Needs documentation
FileSize
65.83 KB

And here is the first patch against our core issue.

Again this is a double patch, so please review only [PATCH] 2/2 (Ctrl-F 2/2).

@todo's here

  • Remove Twig_Markup from theme()
  • Add check_plain to prefix/suffix in drupal_render()?
  • Remove: User error: "content" is an invalid render array key in element_children() (line 6251 of core/includes/common.inc).
  • => @todo: Need to put bugfix into core / probably needs tests
  • Have someone security savvy review this
  • Measure performance
  • Increase performance

The plans to increase performance are:

  • Possibly remove the twig_raw filter again and do it via compile time optimization
  • Allow Attributes to store TwigMarkup directly and not double encode/decode it
  • Optimize creation of Twig_Markups for for-loops (if possible)

Possible followups for security:

Status: Needs review » Needs work
Issue tags: -Needs tests, -Needs documentation

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-6.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review

Testbot: Get to work!

Fabianx’s picture

Another one for the testbot only.

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-10.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
74.97 KB

And another one for testbot, really white space that is not white space is "meh".

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-12.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
76.64 KB

Try again ...

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-14.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
77.51 KB

.

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-16.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
80.13 KB

Exceptions testing ...

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-18.diff, failed testing.

Fabianx’s picture

Fabianx’s picture

Status: Needs work » Needs review

.

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-20.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
83.38 KB

Just trying to pass tests once.

Status: Needs review » Needs work

The last submitted patch, twig-in-core-Show-autoescape-benefits-1712444-22.diff, failed testing.

Anonymous’s picture

Issue summary: View changes

Update issue summary

Fabianx’s picture

Status: Needs work » Needs review
FileSize
65.51 KB

V3 from a secure theme system. Lets see what testbot means ...

Fabianx’s picture

Status: Needs review » Closed (duplicate)
Fabianx’s picture

Status: Closed (duplicate) » Active
Fabianx’s picture

Title: Twig: Show autoescape mode benefits and risks » Twig: Activate autoescape mode

Re-titling

mbrett5062’s picture

@Fabianx, did you mean to leave this 'active'.

Seems to me the patch here was merged back into [#1696706], and that issue is closed 'fixed'.

So can we close this as duplicate again, with your revised title? O do you intend to do more with it?

Fabianx’s picture

#29: Auto escape was not enabled in the original patch. It was stripped out again.

Will work on it once feature freeze is over and we have "rely on autoescape patch progress".

jenlampton’s picture

Removing awesome tag.

David_Rothstein’s picture

There are some other issues open that seem closely related to (or the same as) this one:

#1818266: [meta] A secure theme system (with twig)
#1825952: Turn on twig autoescape by default

Does it make sense to keep this one open too?

moshe weitzman’s picture

Status: Active » Closed (duplicate)

I don't think it does.

moshe weitzman’s picture

Issue summary: View changes

Add new methods of doing secure markup