Skip to content

Commit 5251c02

Browse files
authored
XWIKI-10309: Check URL domains based on a whitelist (#1592)
Introduce a new property for listing the trusted domains and API to check an URL against that list and the aliases used in subwikis. * Add new property url.trustedDomains in xwiki.properties * Add new API in URLConfiguration to retrieve this configuration value * Create a new URLSecurityManager responsible to check if an URL can be trusted based on this property and on the subwikis configurations * Introduce a new listener to invalidate the cache of URLSecurityManager whenever a XWikiServerClass xobject is added/updated/deleted * Move URL API implementations to URL default module * Add a new property url.enableTrustedDomains as a global switch off the checks on domains to avoid breaking behaviours on existing instances * Add a constant property in URLSecurityManager to be set in ExecutionContext to allow temporary switch off the check for extensions * Use both those switches in DefaultURLSecurityManager to prevent performing the check when needed
1 parent 5ce100d commit 5251c02

File tree

40 files changed

+640
-9
lines changed

40 files changed

+640
-9
lines changed

xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyFormAuthenticator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import org.xwiki.security.authentication.AuthenticationFailureManager;
4242
import com.xpn.xwiki.internal.user.UserAuthenticatedEventNotifier;
4343

44+
import com.xpn.xwiki.web.XWikiResponse;
45+
4446
public class MyFormAuthenticator extends FormAuthenticator implements XWikiAuthenticator
4547
{
4648
private static final Logger LOGGER = LoggerFactory.getLogger(MyFormAuthenticator.class);
@@ -244,8 +246,8 @@ public boolean processLogin(String username, String password, String rememberme,
244246

245247
Boolean bAjax = (Boolean) context.get("ajax");
246248
if ((bAjax == null) || (!bAjax.booleanValue())) {
247-
String continueToURL = getContinueToURL(request);
248249
// This is the url that the user was initially accessing before being prompted for login.
250+
String continueToURL = getContinueToURL(request);
249251
response.sendRedirect(response.encodeRedirectURL(continueToURL));
250252
}
251253
} else {

xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/XWikiAction.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,12 @@ protected boolean sendGlobalRedirect(XWikiResponse response, String url, XWikiCo
981981
return false;
982982
}
983983

984+
/**
985+
* Perform a redirect to the given URL.
986+
* @param response the response to use to perform the redirect
987+
* @param url the location of the redirect
988+
* @throws XWikiException in case of IOException when performing the redirect.
989+
*/
984990
protected void sendRedirect(XWikiResponse response, String url) throws XWikiException
985991
{
986992
try {

xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/XWikiServletResponse.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121

2222
import java.io.IOException;
2323
import java.io.PrintWriter;
24+
import java.net.URL;
2425
import java.util.Collection;
2526
import java.util.Locale;
27+
import java.util.regex.Pattern;
2628

2729
import javax.servlet.ServletOutputStream;
2830
import javax.servlet.http.Cookie;
@@ -31,10 +33,12 @@
3133
import org.apache.commons.lang3.StringUtils;
3234
import org.slf4j.Logger;
3335
import org.slf4j.LoggerFactory;
36+
import org.xwiki.url.URLSecurityManager;
3437

3538
public class XWikiServletResponse implements XWikiResponse
3639
{
3740
private static final Logger LOGGER = LoggerFactory.getLogger(XWikiServletResponse.class);
41+
private static final Pattern ABSOLUTE_URL_PATTERN = Pattern.compile("[a-z0-9]+://.*");
3842

3943
private HttpServletResponse response;
4044

@@ -66,9 +70,25 @@ public void sendRedirect(String redirect) throws IOException
6670
LOGGER.warn("Possible HTTP Response Splitting attack, attempting to redirect to [{}]", redirect);
6771
return;
6872
}
73+
74+
// check for trusted domains, only if the given location is an absolute URL.
75+
if (ABSOLUTE_URL_PATTERN.matcher(redirect).matches()) {
76+
if (!getURLSecurityManager().isDomainTrusted(new URL(redirect))) {
77+
LOGGER.warn(
78+
"Possible phishing attack, attempting to redirect to [{}], this request has been blocked. "
79+
+ "If the request was legitimate, add the domain related to this request in the list "
80+
+ "of trusted domains in the configuration.", redirect);
81+
return;
82+
}
83+
}
6984
this.response.sendRedirect(redirect);
7085
}
7186

87+
private URLSecurityManager getURLSecurityManager()
88+
{
89+
return Utils.getComponent(URLSecurityManager.class);
90+
}
91+
7292
@Override
7393
public void setContentType(String type)
7494
{

xwiki-platform-core/xwiki-platform-url/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<!-- Sorted Alphabetically -->
3636
<module>xwiki-platform-url-api</module>
3737
<module>xwiki-platform-url-container</module>
38+
<module>xwiki-platform-url-default</module>
3839
<module>xwiki-platform-url-schemes</module>
3940
</modules>
4041
</project>

xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/pom.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@
3232
<packaging>jar</packaging>
3333
<description>Allows configuration of the URL scheme used by XWiki to parse/serialize URLs</description>
3434
<properties>
35-
<!-- The reason for this low TPC value is because this module is tested using integration tests in the various
36-
URL Scheme modules -->
37-
<xwiki.jacoco.instructionRatio>0.45</xwiki.jacoco.instructionRatio>
35+
<xwiki.jacoco.instructionRatio>0.85</xwiki.jacoco.instructionRatio>
3836
<!-- Name to display by the Extension Manager -->
3937
<xwiki.extension.name>URL API</xwiki.extension.name>
4038
</properties>

xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/src/main/java/org/xwiki/url/URLConfiguration.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
*/
2020
package org.xwiki.url;
2121

22+
import java.util.Collections;
23+
import java.util.List;
24+
2225
import org.xwiki.component.annotation.Role;
26+
import org.xwiki.stability.Unstable;
2327

2428
/**
2529
* Configuration options for the URL module.
@@ -47,4 +51,30 @@ default boolean useResourceLastModificationDate()
4751
{
4852
return true;
4953
}
54+
55+
/**
56+
* Specify the list of domains that are considered as trusted by the administrators of the wiki: those domains can
57+
* be used safely for redirections from the wiki or for performing other requests on them.
58+
* @return the list of trusted domains that can be used in the wiki.
59+
* @since 13.3RC1
60+
* @since 12.10.7
61+
*/
62+
@Unstable
63+
default List<String> getTrustedDomains()
64+
{
65+
return Collections.emptyList();
66+
}
67+
68+
/**
69+
* Define if the trusted domains check should be performed or not. This option is provided only to allow bypassing
70+
* security checks globally on the wiki in case of problems.
71+
* @return {@code true} if the security check on domains should be performed. {@code false} otherwise.
72+
* @since 13.3RC1
73+
* @since 12.10.7
74+
*/
75+
@Unstable
76+
default boolean isTrustedDomainsEnabled()
77+
{
78+
return true;
79+
}
5080
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.url;
21+
22+
import java.net.URL;
23+
24+
import org.xwiki.component.annotation.Role;
25+
import org.xwiki.stability.Unstable;
26+
27+
/**
28+
* Dedicated component to perform security checks on URLs.
29+
*
30+
* @version $Id$
31+
* @since 13.3RC1
32+
* @since 12.10.7
33+
*/
34+
@Role
35+
@Unstable
36+
public interface URLSecurityManager
37+
{
38+
/**
39+
* Constant to be used in {@link org.xwiki.context.ExecutionContext} with the value {@code "true"} to bypass a
40+
* check of {@link #isDomainTrusted(URL)}.
41+
*/
42+
String BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY = "bypassDomainSecurityCheck";
43+
44+
/**
45+
* Check if the given {@link URL} can be trusted based on the trusted domains of the wiki.
46+
* This method check on both the list of trusted domains given by the configuration
47+
* (see {@link URLConfiguration#getTrustedDomains()}) and the list of aliases used by the wiki descriptors.
48+
* Note that this method always returns {@code true} if {@link URLConfiguration#isTrustedDomainsEnabled()} returns
49+
* {@code true}. Also the method will return {@code true} whenever the {@link org.xwiki.context.ExecutionContext}
50+
* contains a property named {@link #BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY} with the value {@code "true"}.
51+
*
52+
* @param urlToCheck the URL for which we want to know if the domain is trusted or not.
53+
* @return {@code true} if the URL domain can be trusted or if the check is skipped, {@code false} otherwise
54+
*/
55+
boolean isDomainTrusted(URL urlToCheck);
56+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<!--
4+
* See the NOTICE file distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This is free software; you can redistribute it and/or modify it
8+
* under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation; either version 2.1 of
10+
* the License, or (at your option) any later version.
11+
*
12+
* This software is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this software; if not, write to the Free
19+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21+
-->
22+
23+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
24+
<modelVersion>4.0.0</modelVersion>
25+
<parent>
26+
<groupId>org.xwiki.platform</groupId>
27+
<artifactId>xwiki-platform-url</artifactId>
28+
<version>13.3-SNAPSHOT</version>
29+
</parent>
30+
<artifactId>xwiki-platform-url-default</artifactId>
31+
<name>XWiki Platform - URL - Default</name>
32+
<packaging>jar</packaging>
33+
<description>Default implementations of the API defined in xwiki-platform-url-api</description>
34+
<properties>
35+
<!-- The reason for this low TPC value is because this module is tested using integration tests in the various
36+
URL Scheme modules -->
37+
<xwiki.jacoco.instructionRatio>0.31</xwiki.jacoco.instructionRatio>
38+
</properties>
39+
<dependencies>
40+
<dependency>
41+
<groupId>org.xwiki.platform</groupId>
42+
<artifactId>xwiki-platform-url-api</artifactId>
43+
<version>${project.version}</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.xwiki.platform</groupId>
47+
<artifactId>xwiki-platform-oldcore</artifactId>
48+
<version>${project.version}</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>org.xwiki.platform</groupId>
52+
<artifactId>xwiki-platform-wiki-api</artifactId>
53+
<version>${project.version}</version>
54+
</dependency>
55+
<!-- Testing Dependencies -->
56+
<dependency>
57+
<groupId>org.xwiki.commons</groupId>
58+
<artifactId>xwiki-commons-tool-test-component</artifactId>
59+
<version>${commons.version}</version>
60+
<scope>test</scope>
61+
</dependency>
62+
</dependencies>
63+
</project>

xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceReferenceSerializer.java renamed to xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceReferenceSerializer.java

File renamed without changes.

xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceTypeResolver.java renamed to xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceTypeResolver.java

File renamed without changes.

0 commit comments

Comments
 (0)