FreeMarker and Java security
Page Contents
In order to understand this section, you will need to have working knowledge of how Java security policy works. A good starting point is the JDK security guides page, look specifically for policy-related documents. On the other hand, if you do not administer a secured Java system, then you probably don't need to know about all this. In this case, feel free to skip this section.
Configuring Java security policy for FreeMarker classes
When FreeMarker is used in a Java virtual machine with a security manager installed, you have to grant it few permissions to ensure it operates properly. Most notably, you need to add these entries to your security policy file for freemarker.jar:
| |||
In certain situations (if FreeMarker attempts to access a thread context class loader that is otherwise foreign to it) you will need to allow it to retrive arbitrary class loaders:
| |||
Additionally, if you are loading templates from a directory, you need to give FreeMarker permissions to read the directory itself as well as the files from that directory using the following permissions:
| |||
I.e., if you're just using the default template loading mechanism which loads templates from the current directory, then specify these permissions additionally: (note that the expression ${user.dir} will be evaluated at run time by the policy interpreter, pretty much as if it were a FreeMarker template)
| |||
Naturally, if you're running under Windows, use double backslash instead of a single slash for separating directory components in paths.
Running Templates in their own security domain
When FreeMarker is used in a Java virtual machine with a security manager installed, the templates are by default run with all the privileges granted to the FreeMarker classes in freemarker.jar.
In many usage scenarios this is acceptable, but sometimes you might want to be able to constrain the privileges of the templates as well as any code that might be further invoked from the templates. The good news is that you can have FreeMarker templates subjected to the Java security policy. For this to work, you need to invoke the setSecure(true) method on your Configuration instance.
When the secure mode is turned on, the Java security policy is applied to the templates just as it is to Java classes. Java security policy assigns privileges based on the concept of "code source". Code source is the URL where the code is loaded from as well as security certificates of its signers, in case it is digitally signed (typically if it comes from a signed JAR file). With this feature turned on, you can specify grant statements in your policy file that also apply to templates, i.e., if your templates reside in /home/johndoe/templates then your policy file can contain a grant entry
| |||
and all privileges specified in that grant statement will apply to templates loaded from that directory and its subdirectories. Note that if the code source of a template is unknown, or no grant privilege matches it, then it will run with the minimal set of privileges granted by the policy to code coming from unknown location, using the grant "" {...} policy entry (it is usually present in the default policy file, and grants only few property read permissions). This is actually okay in most cases - templates simply rendering text from the data-model won't require any additional privileges.
Code source is emitted by the TemplateLoader objects that implement the optional SecureTemplateLoader interface as well. All standard FreeMarker template loaders are secure, meaning that if you use any of them, security settings will be applied to templates correctly. However, if you write your own template loader and don't implement the SecureTemplateLoader interface as well, the templates loaded through it will be treated as unsigned code loaded from unknown location and thus run with no privileges.
If you turn on the secure feature in the configuration, you must grant two additional privileges to FreeMarker classes:
| |||
Actually, "getProtectionDomain" isn't strictly necessary. The code will detect if it doesn't have that permission and will be able to work around it although it'll disable a certain (admittedly quite rare corner case) optimization.
FreeMarker-specific permissions
FreeMarker also introduces a set of permissions specific to itself, and when FreeMarker is used in a JVM with a security manager installed, certain FreeMarker operations will require that the calling code posess these permissions. These are however not too typical, and most of them only apply when secure mode is turned on with the intention of preventing tampering with a secured configuration. All permissions are instances of freemarker.core.FreeMarkerPermission and have a single argument - their name, much like the stock Java runtime permissions do. The following permissions are defined:
-
"modifyTemplate" Permits invocation of various template methods that can be used to modify the template in such a way as to breach security. Specifically getRootTreeNode(), getMacros(), setParent(Configurable), and containingElements(int, int). Only checked when the template's configuration is secure.
-
"setSecure" Permits invocation of setSecure(false) on a secure configuration instance (thus de-securing it).
-
"setScriptEngineConfiguration" See scripting support.
-
"setScriptEngineFactoryConfiguration" See scripting support.
-
"setTemplateLoader"Permits invocation of setTemplateLoader(TemplateLoader) on a secure configuration instance. Since template loaders generate the information about the code source for templates, a malicious template loader could escalate templates' privileges by lying about their source location. Note that various setXxxForTemplateLoading() methods are not checked for this permission, as they internally all create trusted template loaders. If you use your own template loader with a secure configuration, the typical practice to avoid needing this permission is to set the template loader first, and only after that turn on security by calling setSecure(true) on the configuration.
I.e., to grant your own code the ability to modify secured templates, you'd add the following grant statement to your policy:
| |||