Enabling XSS Protection in Plugins

This documentation is for plugin developers.

In Confluence 4.0, the Anti-XSS protection for plugins is enabled by default, but in rare cases when this configuration change breaks an existing plugin, plugin authors may need to take action to ensure that their plugin still works.

On this page:

What is Anti-XSS?

Anti-XSS is a safeguard placed on Velocity template files that automatically HTML encodes inserted variables, therefore protecting against potential cross-site scripting vulnerabilities. It was introduced in Confluence 2.9, and enabled by default in Confluence 3.0 for core Confluence, and then enforced for Confluence core and plugins in Confluence 4.0. It does not apply to any other HTML output generated by plugins. For more information, read the Anti-XSS documentation.

Error rendering macro 'excerpt-include' : No link could be created for 'REV400 Anti-XSS documentation'.

Why should I have my plugin opt in to Anti-XSS protection?

Cross site scripting is a real and dangerous security problem with many web applications. Anti-XSS protects against many potential sources of XSS vulnerabilities. Opting in to Anti-XSS protection requires very little effort, and results in a safer plugin.

Anti-XSS applies automatically to Confluence plugins by default in Confluence 4.0. By explicitly opting in, you may avoid your plugin exposing XSS vulnerabilities if the Confluence admin setting 'Enforce Anti-XSS for plugins' is disabled.

How do I opt in to Anti-XSS protection?

There are three mechanisms to mark that your Velocity template should have Anti-XSS protection applied to it:

  • Give the template's filename a .html.vm suffix (i.e. mypage.html.vm)
  • Place the template in a directory called html (i.e. /templates/html/mypage.vm)
  • Put the Velocity directive call #htmlSafe() somewhere in the template.

If you do any (or any combination) of the above, any variable substitution performed in your Velocity template will be always HTML-encoded under the rules described in the Anti-XSS documentation.

Why would I need my plugin opt out of Anti-XSS protection?

The enforced HTML-encoding may cause some plugins to stop functioning correctly. The symptoms include the following:

  • Raw HTML appears inline, when it should be rendered.
  • JavaScript functions don't activate due to double-encoding.

How do I opt out of Anti-XSS protection?

As of Confluence 4.0, HTML encoding is on for plugins by default.

While we'd recommend that as much of your HTML markup be contained in actual Velocity templates, some templates acquire HTML markup via method calls and property access to Java objects in the Velocity context and very often the result is written directly to the output of the template. In this situation we need to inform the Velocity renderer that these values are intended to contain HTML and should not be encoded when written.

There are a few ways to accomplish this, as noted below.

HtmlSafe method annotation

For values retrieved by calling methods or accessing properties of objects in the context, it is possible to inform the Velocity system that these values are safe to be written without encoding. This is achieved by annotating the method (whether a property getter or not) with the HtmlSafe annotation.

An annotated Java class

import com.atlassian.confluence.velocity.htmlsafe.HtmlSafe;

public class MyContextClass
{
    @HtmlSafe
    public String myMarkupReturningMethod() {
        return "<b>This method returns marked up text!</b>";
    }

    public String myMethodWithAnXssExploit() {
        return "<script>alert('owned');</script>";
    }
}

Using an instance of this class in a template

<ol>
<li>$objectOfMyContextClass.myMarkupReturningMethod()
<li>$objectOfMyContextClass.myMethodWithAnXssExploit()
</ol>
Result when Anti-XSS is disabled
<ol>
<li><b>This method returns marked up text!</b>
<li><script>alert('owned');</script>
</ol>
Result when Anti-XSS is enabled
<ol>
<li><b>This method returns marked up text!</b>
<li>&lt;script&gt;alert('owned');&lt;/script&gt;
</ol>

Method naming convention

Retrofitting this type of behaviour into an existing, significant codebase with an extensive plugin catalogue is very difficult and we'd like to make this new behaviour fit in as well as possible with the existing body of work. For this reason certain methods will automatically be deemed as being HtmlSafe:

  • Those that start with render or getRender
  • Those that end with Html

This strategy fits in with the observation that many of the existing methods that return HTML were named according to this convention.

Well known HTML returning methods

A few often used methods are known to return HTML by contract. These methods are therefore also treated as HtmlSafe by default.

  • com.opensymphony.util.TextUtils#htmlEncode
  • com.opensymphony.webwork.util.VelocityWebWorkUtil#htmlEncode

This means that any uses of these methods will behave identically whether or not the anti-XSS mode is engaged. It is important to note that GeneralUtil.htmlEncode() has been annotated as HtmlSafe and will also behave identically without any modification to uses in templates.

Reference naming convention

To cater for cases where HTML strings are built entirely in a Velocity template and then rendered, it is possible to avoid the auto encoder by using a "Html" suffix on the reference name.

Template

#set ($someHtml = "<p>This is a paragraph</p>")
#set ($some = $someHtml)

<ul>
<li>$someHtml
<li>$some
</ul>

Output

<ul>
<li><p>This is a paragraph</p>
<li>&lt;p&gt;This is a paragraph&lt;/p&gt;
</ul>

Transitional reference name exclusion

The velocity template reference $body will also avoid automatic encoding for the time being. Many templates use this convention to include whole slabs of HTML sourced from other rendering mechanisms. This exclusion is very likely to be removed in the future so it is strongly recommended that all such references be changed to make use of the standard "html" suffix as described previously.

Using the 'Disable Anti-XSS' directive in a Velocity Template

Add the following velocity directive to your template:

#disableAntiXSS()

This will prevent variables in your template being HTML encoded automatically.

Migration strategies for template authors

To ensure that your HTML markup will function correctly now and in the future here are some guidelines of working with the Anti-XSS feature:

  • Try to move all of your HTML markup to Velocity templates – The more that your markup is contained in templates, the less intrusive the automatic encoding system will be. This is a good design choice in general as markup in templates is far more maintainable than static strings in Java classes.
  • Mark any other HTML data as being HtmlSafe – methods that return HTML markup that cannot be contained in templates such as data sourced from user input or other remote retrieval need to be marked as HtmlSafe or assigned to a Velocity reference ending in the string Html before use. Consider using the HtmlFragment class for a richer, HtmlSafe description of the data that you are returning. The fewer sources of HtmlSafe data the better the security of the system.
  • Move away from relying on the transitional $body reference encoding exclusion – To keep the system as consistent as possible, usages of $body in templates that include HTML fragements should be changed to use either a "html" suffix or the HtmlFragment class.
  • To test your plugins, change the admin setting XSS protection for plugins on the Confluence Admin > Security > Security configuration page – you can enable and disable the automatic encoding functionality in Confluence via this setting.
  • Raise any issues you have – if you think we can do something better or make it easier for you to write templates and plugins that support this new mechanism we'd love to hear from you.

Developers interested in more advanced details and use-cases should consult the Advanced HTML encoding documentation.

Caveats

As much as we'd love to make the new HTML encoding system transparent to use there are a few things that you need to watch out for.

Velocity string interpolation

The Velocity configuration of Confluence allows you to use reference interpolation in any strings you construct in a Velocity template.

#set ($myVar = "<p>Here is a paragraph</p>")
#set ($myHtml = "$myVar <p>A second paragraph</p>")

Here it is: $myHtml
Here it is: &lt;p&gt;Here is a paragraph&lt;/p&gt; <p>A second paragraph</p>

As can be seen from this example, automatic HTML encoding will occur when references are interpolated inside strings in the same manner as when they are written to the template output. At present there is no way to treat this case specially and you will need to make sure that any data used as part of interpolation is being treated correctly by the encoder.

String parameters

Occasionally you may have some code in your velocity template that makes a call back to some Java logic. To make sure that the value is being protected by the Anti-XSS mechanism, you must have the string evaluate within the velocity template. If not, you are passing a reference into the Java code which will not be protected.

You should write the velocity template like this:

$object.doSomething("$action.getValue()")

The quotes around the $action.getValue() call mean velocity will evaluate it before passing it into object.doSomething() and have a chance to be automatically encoded before being passed to the Java method.

Accessing action context values

Templates rendered from a Webwork Velocity result are able to access values on Webwork's action stack as if they were entries in the Velocity context. If these values are sourced from getter methods on the current action the automatic encoding system cannot detect whether the getter method has been marked as HtmlSafe. In this situation the value will be automatically encoded when rendered regardless of any annotation or method naming convention used by the source of the value.

To remedy this either use the HtmlSafe reference naming convention (e.g. assigning the action context value to a context variable ending with Html before rendering) or retrieve the value directly from the current action via the $action reference.

Unexpected context types

Some Java code may use the Velocity context as a data passing mechanism to collect information from a template after it is rendered.

public class DataHolder {
    @HtmlSafe
    public String getHtml() {
        return "<strong>My html</strong>";
    }
}
myTemplate
#set ($result = data.getHtml())
...
Template myTemplate = getTemplate();
Context myContext = new VelocityContext();
myContext.put("data", new DataHolder());

renderTemplate(myTemplate, myContext);

String message = (String) myContext.get("result");

The above Java code will fail with a ClassCastException at runtime because the reference $result will not be an instance of String but an instance of BoxedValue due to the way that Confluence's Velocity runtime handles HtmlSafe values in the Velocity context. If there is demand it is feasible for type compatibility to be restored in this situation via the use of a transparent, unboxing context layer but in general this mechanism of information passing is discouraged. Context values that are not set from HtmlSafe sources are not affected in this situation.

How does HTML encoding work?

For this mode of behaviour, there are two parts of the system:

  1. A mechanism for marking data as being safe for HTML rendering.
  2. A mechanism for encoding any data not marked as safe as it is being written to the output.

A note on naming

You may notice that the #htmlSafe() velocity directive (which causes a template to opt in to Anti-XSS protection) has the opposite meaning to the @HTMLSafe Java annotation (which causes a Java method to opt out of Anti-XSS protection). We regret this confusing naming and hope to fix it in a future release. We will, however, ensure that #htmlSafe() continues to work.

Related topics

Anti-XSS documentation
Advanced HTML encoding
Preventing XSS issues with macros in Confluence 4.0

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport