dened
dened

Reputation: 4310

How to escape HTML by default in StringTemplate?

It is very good practice in HTML template engines to HTML-escape by default placeholder text to help prevent XSS (cross-site scripting) attacks. Is it possible to achieve this behavior in StringTemplate?

I have tried to register custom AttributeRenderer which escapes HTML unless format is "raw":

stg.registerRenderer(String.class, new AttributeRenderer() {
    @Override
    public String toString(Object o, String format, Locale locale)  {
        String s = (String)o;
        return Objects.equals(format, "raw") ? s : StringEscapeUtils.escapeHtml4(s);
    }
});

But it fails because in this case StringTemlate escapes not only placeholder text but also template text itself. For example this template:

example(title, content) ::= <<
    <html>
        <head>
            <title>$title$</title>
        </head>
        <body>
            $content; format = "raw"$
        </body>
    </html>
>>

Is rendered as:

&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Example Title&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        <p>Not escaped because of <code>format = "raw"</code>.</p>
    &lt;/body&gt;
&lt;/html&gt;

Can anybody help?

Upvotes: 4

Views: 1511

Answers (2)

Ryan
Ryan

Reputation: 8005

There is no good solution to encode by default. The template is passed through the AttributeRenderer for the string data type, and there is no context information to detect if it is processing the template or a variable. So all strings, including the template, are encoded by default since you cannot specify "raw" for the template.

An alternative solution is to use format="xml-encode" in the variables that need to be encoded. The built-in StringRenderer has support for several formats:

  • upper
  • lower
  • cap
  • url-encode
  • xml-encode

So your example would be:

example(title, content) ::= <<
    <html>
        <head>
            <title>$title; format="xml-encode"$</title>
        </head>
        <body>
            $content$
        </body>
    </html>
>>

In order to encode by default, you have limited options. The alternatives are:

  1. Use a custom data type (not String) for your variables, so you can register your HtmlEscapeStringRenderer for the custom data type. This is difficult if you use complex objects as variables that are already using standard strings.
  2. Add the raw and the escaped variables to the model manually, e.g. add title (escaped) and title_raw (raw). You do not need a custom AttributeRenderer in this case. StringTemplate has a strict view/model separation and you need to have the model populated before it is rendered with both the raw and escaped values.

Neither option is particularly desirable, but I do not see any other alternatives with StringTemplate4.

Upvotes: 3

John Cromartie
John Cromartie

Reputation: 4224

The answer is to revert to StringTemplate v3.

Upvotes: 1

Related Questions