Wiki source code of Security
Last modified by Thomas Mortagne on 2024/03/15
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | This page aims at listing the specific things that a developer should be careful with to avoid introducing new vulnerabilities in scripts and extensions. All security topic related to administration of the wiki is located in [[the security page of the administrator guide>>doc:Documentation.AdminGuide.Security]]. | ||
2 | |||
3 | {{box cssClass="floatinginfobox" title="**Contents**"}} | ||
4 | {{toc/}} | ||
5 | {{/box}} | ||
6 | |||
7 | == Scripting and Escaping == | ||
8 | |||
9 | The first vulnerability in scripts is the user inputs: any input that a user can provide could possibly be an open door to an attack. Either XSS when the content is output in an HTML context, or XWiki syntax injection when the syntax is injected, e.g., in a Velocity macro where parsing of the output is enabled (the default). It doesn't matter where in the output the user's input is used. Regardless if it is in a parameter, an HTML macro or a verbatim syntax, by including the respective closing syntax, user input can always close whatever syntax it is part of. The nested script macro protection is no protection against attacks. By putting the nested script macro, e.g., inside an async macro, the nested script macro protection can easily be circumvented as the async macro has its own parsing context. | ||
10 | |||
11 | So in order to mitigate this, developers should always ensure to use the proper escaping mechanism. The most important ways to escape content are: | ||
12 | |||
13 | * ##$services.rendering.escape($content, 'xwiki/2.1')## for XWiki syntax | ||
14 | * ##$escapetool.xml($content)## for HTML output. This can also be used in an HTML macro and escapes ##{##, thereby preventing the closing of the HTML macro through user input. | ||
15 | |||
16 | Make sure you always test if escaping actually protects against attacks by writing appropriate tests. | ||
17 | |||
18 | === ##xwiki/2.0## and ##xwiki/2.1## syntaxes === | ||
19 | |||
20 | ==== Link label ==== | ||
21 | |||
22 | In XWiki syntax 2.0 and 2.1 the link is parsed in two passes, each pass having its own escaping: | ||
23 | * the global link is first parsed with the label being just one big string | ||
24 | * then the label is parsed on its own | ||
25 | |||
26 | What this means in practice is that when you need to escape something in the link label you need to escape it twice. For example if you want to print something that may contains wiki syntax as a link label you could do for example in Velocity: | ||
27 | |||
28 | {{code language="velocity"}} | ||
29 | #set ($userContent = '{{mymacro/}}') | ||
30 | #set ($escapedLabel = $services.rendering.escape($services.rendering.escape($userContent, 'xwiki/2.1'), 'xwiki/2.1')) | ||
31 | [[label $escapedLabel>>Main.WebHome]] | ||
32 | {{/code}} | ||
33 | |||
34 | ==== Verbatim ==== | ||
35 | |||
36 | It's impossible to properly escape content to put in [[verbatim syntax>>https://jira.xwiki.org/browse/XRENDERING-686]] in syntaxes ##xwiki/2.0## and ##xwiki/2.1##. | ||
37 | |||
38 | The simplest for this kind of use case is generally to use something like: | ||
39 | |||
40 | {{code language="velocity"}} | ||
41 | (%class="code"%)((( | ||
42 | $services.rendering.escape($doc.content, 'xwiki/2.1') | ||
43 | ))) | ||
44 | {{/code}} | ||
45 | |||
46 | ==== Code macro ==== | ||
47 | |||
48 | It's impossible to properly escape content to put in [[code macro>>https://jira.xwiki.org/browse/XRENDERING-13]] in syntaxes ##xwiki/2.0## and ##xwiki/2.1##. | ||
49 | |||
50 | There are several alternatives if you need to highlight user input: | ||
51 | |||
52 | {{version since="14.10.2"}} | ||
53 | Use the ##source## code macro parameter: instead of trying to escape the content you provide only a reference of a the content to highlight so no need to escape it anymore. | ||
54 | |||
55 | See [[extensions:Extension.Code Macro||anchor="HSource"]] for more details. | ||
56 | {{/version}} | ||
57 | |||
58 | {{version before="14.10.2"}} | ||
59 | An alternative if you need to highlight user input is to return directly the MacroBlock instead of serializing it. For example in Groovy: | ||
60 | |||
61 | {{code language="groovy"}} | ||
62 | return new org.xwiki.rendering.block.MacroBlock("code", ["language": "xml"], userInput, false) | ||
63 | {{/code}} | ||
64 | {{/version}} | ||
65 | |||
66 | == Restricted Mode in macros == | ||
67 | |||
68 | As explained in details [[in the documentation for writing macros>>rendering:Main.ExtendingMacro||anchor="HSecurityconsiderations"]], the Macro Transformation Context can be set in "Restricted Mode" and in your macro should respect this parameter (by checking ##macroContext.getTransformationContext().isRestricted()##) and either not execute at all or execute in a restricted mode. | ||
69 | |||
70 | == Protect against XXE attacks == | ||
71 | |||
72 | Always follow the [[OWASP recommendations to protect against XXE attacks>>https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html]] when parsing XML. | ||
73 | |||
74 | == Right Checks in Script Services == | ||
75 | |||
76 | Any code that is exposed as a script service needs to check the rights of the context **author**, i.e., the user who wrote the script, in addition to the context **user**, i.e., the user that is accessing the script. Currently, the only easy way to check rights of the context author is to check script or programming right using a contextual authorization manager. It takes important context information into account like if permissions have been dropped. In addition to that, all right checks that are done for the context user should be duplicated for the context author to ensure that no CSRF attacks are possible, i.e., there is no way to, e.g., write a script that executes a dangerous action as soon as a user with more rights accesses the document. It needs to be taken care that if permissions have been dropped, the context author cannot be trusted and thus no dangerous actions must be performed and no sensitive information must be disclosed. | ||
77 | |||
78 | If the script service exposes information or executes actions without further right checks, it must check for programming right of the context author. | ||
79 | |||
80 | Note that context author rights are currently not consistently enforced in XWiki, in particular there is no such concept in JavaScript. This is an area for future improvements, new code should still take context author rights into account. | ||
81 | |||
82 | == Returning Data in Script Services == | ||
83 | |||
84 | When returning any object in a script service, ensure that all its methods properly check access rights and don't allow modifying data without proper access right checks. Use wrapper objects to add right checks or hide dangerous methods. For example, returning an ##XWikiDocument## is not safe as it allows modifying author information and executing the content with the new author. | ||
85 | |||
86 | == Executing Code or XWiki Syntax == | ||
87 | |||
88 | If possible, it should be avoided to introduce new code that directly executes (Velocity) code or XWiki syntax with transformations. Instead, existing APIs should be used, e.g., displaying a text area property instead of manually parsing the content of the property. If this should still be necessary, it is of utmost importance to: | ||
89 | |||
90 | * Check that the author of the code has script right. Make sure you check the content author if the code is in the content of the document and the effective metadata author if the code is in an XObject. | ||
91 | * Execute the code or transformations with the correct author in context. In Java, ##AuthorExecutor## should be used for this. There is no way to do this in Velocity. There are hacks like ##dropPermissions## but they are prone to security vulnerabilities and should thus be avoided. | ||
92 | |||
93 | == Safe evaluation of objects == | ||
94 | |||
95 | {{version since="14.10.21,15.5.5,15.10.2"}} | ||
96 | A new API has been introduced, allowing to specify exactly the XObjects properties that needs to be evaluated and how. | ||
97 | |||
98 | This includes a new [[ObjectEvaluator>>https://github.com/xwiki/xwiki-platform/blob/xwiki-platform-15.10.2/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/evaluation/ObjectEvaluator.java]] component, that can be implemented with a hint matching the name of the XClass for which a safe evaluation is required. Implementations of [[ObjectPropertyEvaluator>>https://github.com/xwiki/xwiki-platform/blob/xwiki-platform-15.10.2/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/evaluation/ObjectPropertyEvaluator.java]] can be used to provide different evaluation strategies: an existing implementation already exists for Velocity evaluation of properties, with the hint ##velocity##. For a full example of an ##ObjectEvaluator## component, see [[the one for SearchSuggestSourceClass XClass>>https://github.com/xwiki/xwiki-platform/blob/xwiki-platform-15.10.2/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-api/src/main/java/org/xwiki/search/internal/SearchSuggestSourceObjectEvaluator.java]]. | ||
99 | |||
100 | Finally once the component is declared, the object properties can be safely evaluated by calling ##evaluate()## on the object instance, which will return the map of evaluated properties. | ||
101 | {{/version}} |