Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
Nobody wants a website that can be hacked. Drupal has a great security track record and works hard to ensure that core and contributed modules are safe for everyone to use. One of the most common types of security issue is a cross-site scripting attack (XSS). In Drupal 8 we've made extensive changes to the theme system that reduce XSS vulnerabilities.
In previous versions of Drupal, developers had to be very careful not to cause a security issue by printing variables in templates without considering their source. For example, the Drupal 7 handbook page for handling text in a secure fashion shows the following examples for printing variables in templates:
Bad:
print '<a href="/..." title="' . $title . '">view node</a>';
Good:
print '<a href="/..." title="' . check_plain($title) . '">view node</a>';
The Drupal 7 best practice places multiple demands upon developers and makes maintaining secure code complicated. One problem is that the developer cannot know if the $title variable in the example has already been escaped in other code. If the developer calls check_plain() on something that has already been escaped with check_plain(), it will be double-escaped. Double escaping turns sensible markup like this:
<p>Copyright © 2016</p>
into this:
<p>Copyright &copy 2016</p>
Another problem is that the developer might actually want to print markup that is included in the variable, but has no way of knowing whether that markup is safe. And just to complicate matters further, at the time the template is created, a variable might be completely safe for output, but later, a contributed module could be enabled that alters the variable and makes it unsafe to use without check_plain().
Drupal 8 has a new template engine called Twig. The work done to integrate Twig with Drupal 8 has brought a number of benefits including:
It's this last benefit that means developers no longer need to work out which output is unsafe and run it through check_plain() (nor the Drupal 8 equivalent, Html::escape()).
Take a simple Twig template:
<div>{{ variable }}</div>
If the variable is a string, it will be automatically escaped. If the template has access to a node object, for example, and the title is printed using {{ node.title }}, that will be automatically escaped as well.
However, we don't always want to autoescape variables. For example, the header is printed in the page.html.twig template like so:
<header role="banner">{{ page.header }}</header>
The {{ page.header }} variable is a Markup object created by the render system. It is not escaped because it implements the MarkupInterface.
$form['#title'] = $this->t('How do <em>you</em> like your coffee?');
The #title element here is using $this->t() to generate translatable markup. It returns aTranslatableMarkup object which also implements MarkupInterface (just like the output of the render system). This means that the render system will not escape this text and browsers will mark up the "you" with emphasis.
One of the interesting things about translations is that the English version might not need markup, but the translation still might. For example, it is possible the translator might want to use the BDO tag to switch the direction of the language. Since all translations areTranslatableMarkup objects in Drupal 8, developers do not need to worry about whether a translation contains HTML or not. This is a significant improvement over previous versions of Drupal, which did not integrate translatable strings with the render system.
Automatic escaping in Drupal 8 is a great feature that makes developing secure modules and themes much simpler. The next post in this series will look into what this means for developing modules and, specifically, how to markup should be joined together. In Drupal 8 the following code does not work!
t('Concatenating <em>markup') . ' ' . t('objects</em> does not work.')
Bình luận (0)
Add Comment