Looking at recently published security advisories like CVE-2022-29251 it is apparent that it is very easy to introduce security vulnerabilities in XWiki as by default output from Velocity isn’t escaped in any way. This means that every time you output a value, you need to actively remember that it needs to be escaped - or you need to decide that this value is safe and doesn’t need escaping. Modern UI frameworks like React or Vue.js escape all values by default which is very effective at preventing security issues. I think we should include such secure-by-default templates for server-side rendering in XWiki and strongly encourage their use over direct output from Velocity. The main motivation for me is to make it easy to write secure code without requiring much thinking.
I would formulate the following requirements:
- Support for both XWiki syntax and HTML with similar syntax
- Support for the existing script context such that no new API needs to be created and variables (and maybe even macros) defined in Velocity can be accessed
- A syntax that is not executed by Velocity such that it can be used in Velocity macros and templates (would need extra post-processing, though, for templates, not sure if we want to do this)
There are existing frameworks like Thymeleaf in Java which support templates with parameters prefixed by th:
that include automatic escaping of the used value:
<input type="text" name="userName" value="James Carrot" th:value="${user.name}" />
They also support the special text
attribute to set the content of an element. This syntax is incompatible with Velocity so this would fail the third requirement but we should check how much this can be customized. For XWiki syntax I imagine something similar, using the existing parameter syntax:
(% xw:id="user.id" xw:text="user.name" %)
= User Name =
where “User Name” would be replaced by the user’s name. Similarly, this could also support parameters in macros and references.
This kind of parameter support typically also supports simple loops and if-statements such that simple display logic can be directly implemented in the template using special “if” and “each” attributes, see the Thymeleaf Tutorial for some examples.
While the creation of a special version of the HTML macro for such a parameter syntax should be relatively straightforward, the use in XWiki syntax creates some questions:
- Should we support more parameter types than just simple strings for macros? This could be interesting to create macros that would, e.g., display an XObject that is passed as parameter.
- In which order are these parameters parsed, in particular in combination with macros? As these parameters could reference values from velocity macros, they should be parsed after velocity macros, on the other if there is an
if
-parameter on some higher-level element, this should prevent parsing the velocity macro, so I think this would need to be mixed with macro execution in a clever way. - We would need a strategy how to transform these special parameters into valid HTML (
data-
)-attributes without parsing in the annotated HTML renderer such that they can be preserved in the WYSIWYG editor. In particular for macros, this might also be challenging and we might need to disable the execution of macros that require parameters in the context of annotated HTML.
All in all, this doesn’t seem easy and I’m wondering if it would be better to restrict this parameter syntax to syntax parsed in special macros, or in other words: just apply this parameter processing to the XDOM that is parsed from the content of a new macro.
I’ve also no idea when this could be implemented, this totally depends on the complexity (which is why I would prefer to keep this as simple as possible) and if somebody has the time to actually implement it. In the end I hope this will actually save time, though, as it should hopefully make the development easier as you need to think less about escaping and it will prevent security issues which create a huge cost later not only for fixing and documenting them but also in terms of potential harm they could cause. Therefore, I hope we can implement this as soon as possible such that new code can be written using the new parameter support and existing code can be migrated to use it.
Any opinions? Ideas? Any suggestions for frameworks we could use for parameter content parsing?