Как избежать HTML по умолчанию в StringTemplate?

В механизмах HTML-шаблонов очень полезно использовать HTML-экранирование по умолчанию для текста-заполнителя, чтобы предотвратить атаки XSS (межсайтовый скриптинг). Можно ли добиться такого поведения в StringTemplate?

Я пытался зарегистрировать пользовательский AttributeRenderer который избегает HTML, если format является "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);
    }
});

Но это терпит неудачу, потому что в этом случае StringTemlate экранирует не только текст заполнителя, но и сам текст шаблона. Например этот шаблон:

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

Представляется как:

&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;

Кто-нибудь может помочь?

2 ответа

Нет хорошего решения для кодирования по умолчанию. Шаблон передается через AttributeRenderer для строкового типа данных, и нет никакой контекстной информации, чтобы определить, обрабатывает ли он шаблон или переменную. Таким образом, все строки, включая шаблон, кодируются по умолчанию, поскольку вы не можете указать "raw" для шаблона.

Альтернативное решение заключается в использовании format="xml-encode" в переменных, которые должны быть закодированы. Встроенный StringRenderer имеет поддержку нескольких форматов:

  • верхний
  • ниже
  • крышка
  • URL-кодирование
  • XML-кодирование

Итак, ваш пример будет:

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

Для того, чтобы кодировать по умолчанию, у вас есть ограниченные возможности. Альтернативы:

  1. Используйте пользовательский тип данных (не String) для ваших переменных, чтобы вы могли зарегистрировать HtmlEscapeStringRenderer для пользовательского типа данных. Это сложно, если вы используете сложные объекты в качестве переменных, которые уже используют стандартные строки.
  2. Добавьте необработанные и экранированные переменные в модель вручную, например, добавьте title (сбежал) и title_raw (Сырье). В этом случае вам не нужен пользовательский AttributeRenderer. StringTemplate имеет строгое разделение вида / модели, и вам необходимо заполнить модель, прежде чем она будет отображена как с необработанными, так и с экранированными значениями.

Ни один из вариантов не является особенно желательным, но я не вижу никаких других альтернатив с StringTemplate4.

Ответ - вернуться к StringTemplate v3.

Другие вопросы по тегам