java Freemarker 中的默认转义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1265488/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:51:53  来源:igfitidea点击:

Default escaping in Freemarker

javaxssescapingfreemarker

提问by Massimiliano Fliri

In Freemarker templates we can use the escape directive to automatically apply an escaping to all interpolations inside the included block:

在 Freemarker 模板中,我们可以使用转义指令自动将转义应用于包含块内的所有插值:

<#escape x as x?html>
  <#-- name is escaped as html -->
  Hallo, ${name}
</#escape>

Is there a way to programmatically achieve a similar effect, defining a default escape applied to all interpolations in the template, including those outside escape directives?

有没有办法以编程方式实现类似的效果,定义应用于模板中所有插值的默认转义,包括那些外部转义指令?

Thanks.

谢谢。

回答by Peter Becker

To elaborate on Attila's answer: you can use a class like this oneand then wrap your template loader like this:

详细说明 Attila 的答案:您可以使用这样的类,然后像这样包装模板加载器:

final TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), templatePath) {
  /**
   * Replaces the normal template reader with something that changes the default
   * escaping to HTML as to avoid XSS attacks.
   */
  @Override
  public Reader getReader(Object templateSource, String encoding) throws IOException {
     return new WrappingReader(super.getReader(templateSource, encoding), "<#escape x as x?html>", "</#escape>");
  }
};

If you don't include linebreaks in the added parts you don't get the line numbering problem. You can't use the <#ftl>/[#ftl] with this approach, though.

如果您不在添加的部分中包含换行符,则不会遇到行号问题。但是,您不能通过这种方法使用 <#ftl>/[#ftl]。

回答by ddekany

Since 2.3.24 each template has an associated freemarker.core.OutputFormatobject, which specifies if and how ${...}(and #{...}) is escaped. OuputFormatfor HTML, XML and RTF are provided out of the box, but you can also define your own formats. When the selected OutputFormatescapes by default, then you can prevent escaping explicitly like ${foo?no_esc}.

从 2.3.24 开始,每个模板都有一个关联的freemarker.core.OutputFormat对象,它指定是否以及如何转义${...}(和#{...})。OuputFormat对于 HTML、XML 和 RTF 是开箱即用的,但您也可以定义自己的格式。当所选OutputFormat逃逸默认情况下,您可以防止显式逃逸${foo?no_esc}

There are several ways of associating templates with the OutputFormatyou want. For HTML and XML escaping, the recommended way is setting the recognize_standard_file_extensionsconfiguration setting to true, then using ftlhfile extension for HTML, and ftlxfile extension for XML templates. You can also associate OutputFormat-s to templates based on arbitrary template name (template path) patterns, using the template_configurerssetting. Last not least, you can just set the default output format globally like configuration.setOutputFormat(HTMLOutputFormat.INSTANCE). You can also override the output format at the top of the template as <#ftl output_format='HTML'>, though it should be used rarely.

有多种方法可以将模板与OutputFormat您想要的相关联。对于 HTML 和 XML 转义,推荐的方法是将recognize_standard_file_extensions配置设置设置为true,然后ftlh对 HTML使用文件扩展ftlx名,对 XML 模板使用文件扩展名。您还可以OutputFormat使用template_configurers设置将-s关联到基于任意模板名称(模板路径)模式的模板。最后同样重要的是,您可以像configuration.setOutputFormat(HTMLOutputFormat.INSTANCE). 您还可以将模板顶部的输出格式覆盖为<#ftl output_format='HTML'>,尽管它应该很少使用。

Related documentation pages: http://freemarker.org/docs/dgui_misc_autoescaping.html, http://freemarker.org/docs/pgui_config_outputformatsautoesc.html

相关文档页面:http: //freemarker.org/docs/dgui_misc_autoescaping.html、http: //freemarker.org/docs/pgui_config_outputformatsautoesc.html

回答by Stefan Norberg

The suggested TemplateLoaders in the links need a little tweaking if you are using <#include parse=false .../> to include for example HTML in your templates.

如果您使用 <#include parse=false .../> 将例如 HTML 包含在您的模板中,则链接中建议的 TemplateLoaders 需要稍作调整。

Also, you need to copy spring.ftl and use your own copy with the <#ftl ..> directive on top removed like Tom said.

此外,您需要复制 spring.ftl 并使用您自己的副本,并像汤姆所说的那样删除顶部的 <#ftl ..> 指令。

The following works well, although a bit rough (using guava over commons-io)

以下效果很好,虽然有点粗糙(在 commons-io 上使用番石榴)

@Override  
public Reader getReader(Object pTemplateSource, String pEncoding) throws IOException {  
   Reader tReader = delegate.getReader(pTemplateSource, pEncoding);  
   try {  
       String tTemplateText = CharStreams.toString(tReader);

       //only include files ending with "ftl", as we may have some parse=false on included html files
       if (pTemplateSource.toString().endsWith("ftl")) {
           return new StringReader(ESCAPE_PREFIX + tTemplateText + ESCAPE_SUFFIX);
       }
       return new StringReader(tTemplateText);
   } finally {  
       Closeables.closeQuietly(tReader);  
   }  
} 

回答by Attila Szegedi

There is a solution, although it's not entirely trivial. You can create a special TemplateLoader that wraps other template loaders, and injects <#escape x as x?html> in the prolog of the template source text, and adds as the epilogue of it.

有一个解决方案,尽管它并不完全是微不足道的。您可以创建一个特殊的TemplateLoader 来包装其他模板加载器,并在模板源文本的prolog 中注入<#escape x as x?html>,并添加为它的epilogue。

Obvious drawbacks: - column numbers in first line will be thrown off - if your template starts with <#ftl> declaration, you need to insert <#escape> after it.

明显的缺点: - 第一行的列号将被丢弃 - 如果您的模板以 <#ftl> 声明开头,则需要在其后插入 <#escape>。

回答by Tom

You don't actually need a WrappingReader to add the escapes. You can just create a decorator around any TemplateLoader, read in the template into a String, wrap the template text in escapes and then return a StringReader that reads the resulting String. To see how that's done take a look here. The only gotcha that I've found is that if you use this approach and include the spring.ftl macros from the classpath they will blow up since they have a <#ftl> declaration at the very top. You can however simply copy spring.ftl into your template path and remove the declaration (and all the escaping directives since you will be escaping by default).

您实际上并不需要 WrappingReader 来添加转义符。您可以在任何 TemplateLoader 周围创建一个装饰器,将模板读入一个字符串,将模板文本包装在转义符中,然后返回一个读取结果字符串的 StringReader。要了解这是如何完成的,请查看此处。我发现的唯一问题是,如果您使用这种方法并在类路径中包含 spring.ftl 宏,它们将爆炸,因为它们在最顶部有一个 <#ftl> 声明。但是,您可以简单地将 spring.ftl 复制到模板路径中并删除声明(以及所有转义指令,因为默认情况下您将进行转义)。