summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2013-04-25 12:45:45 +0300
committerVaadin Code Review <review@vaadin.com>2013-04-25 12:15:48 +0000
commita46c97bd7936ea8793618bb54ce19ac32c61f71d (patch)
treed66c1be61070be9620f8107011bd8a372a9e7a72 /server/src
parent220b1150ca411a63009d7f30e0400dc062f10c27 (diff)
downloadvaadin-framework-a46c97bd7936ea8793618bb54ce19ac32c61f71d.tar.gz
vaadin-framework-a46c97bd7936ea8793618bb54ce19ac32c61f71d.zip
Verify CSRF token before accepting new CSRF connection (#11635)
* Can't open push connection during client-side init because CSRF token is not available at that point. This allows simplifying the initialization because the push state will not be checked until the first response has been processed. * Add helper for checking the CSRF token Change-Id: I31da1ac669dc9a581cbd66f58c07f10ea4b8b676
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java2
-rw-r--r--server/src/com/vaadin/server/VaadinService.java39
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java37
-rw-r--r--server/src/com/vaadin/server/communication/ServerRpcHandler.java26
-rw-r--r--server/src/com/vaadin/server/communication/UIInitHandler.java8
-rw-r--r--server/src/com/vaadin/ui/UI.java4
6 files changed, 78 insertions, 38 deletions
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java
index e83b2dfdef..dddfb385a6 100644
--- a/server/src/com/vaadin/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/server/BootstrapHandler.java
@@ -526,8 +526,6 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
appConfig.put("heartbeatInterval", vaadinService
.getDeploymentConfiguration().getHeartbeatInterval());
- appConfig.put("pushMode", context.getPushMode().toString());
-
String serviceUrl = getServiceUrl(context);
if (serviceUrl != null) {
appConfig.put(ApplicationConstants.SERVICE_URL, serviceUrl);
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index 6088fa55ca..11060c6f73 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -52,6 +52,7 @@ import com.vaadin.server.communication.HeartbeatHandler;
import com.vaadin.server.communication.PublishedFileHandler;
import com.vaadin.server.communication.SessionRequestHandler;
import com.vaadin.server.communication.UidlRequestHandler;
+import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.JsonConstants;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.ui.UI;
@@ -1481,4 +1482,42 @@ public abstract class VaadinService implements Serializable {
return false;
}
+ /**
+ * Verifies that the given CSRF token (aka double submit cookie) is valid
+ * for the given session. This is used to protect against Cross Site Request
+ * Forgery attacks.
+ * <p>
+ * This protection is enabled by default, but it might need to be disabled
+ * to allow a certain type of testing. For these cases, the check can be
+ * disabled by setting the init parameter
+ * {@value Constants#SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION} to
+ * <code>true</code>.
+ *
+ * @see DeploymentConfiguration#isXsrfProtectionEnabled()
+ *
+ * @since 7.1
+ *
+ * @param session
+ * the vaadin session for which the check should be done
+ * @param requestToken
+ * the CSRF token provided in the request
+ * @return <code>true</code> if the token is valid or if the protection is
+ * disabled; <code>false</code> if protection is enabled and the
+ * token is invalid
+ */
+ public static boolean isCsrfTokenValid(VaadinSession session,
+ String requestToken) {
+
+ if (session.getService().getDeploymentConfiguration()
+ .isXsrfProtectionEnabled()) {
+ String keyInSession = (String) session.getSession().getAttribute(
+ ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
+
+ if (keyInSession == null || !keyInSession.equals(requestToken)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
}
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index bdc8c723a5..c9d451509c 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -38,6 +38,7 @@ import com.vaadin.server.VaadinServletRequest;
import com.vaadin.server.VaadinServletService;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.WebBrowser;
+import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.UI;
@@ -70,15 +71,34 @@ public class PushHandler implements AtmosphereHandler {
"New push connection with transport {0}",
resource.transport());
resource.getResponse().setContentType("text/plain; charset=UTF-8");
+
+ VaadinSession session = ui.getSession();
if (resource.transport() == TRANSPORT.STREAMING) {
// IE8 requires a longer padding to work properly if the
// initial message is small (#11573). Chrome does not work
// without the original padding...
- WebBrowser browser = ui.getSession().getBrowser();
+ WebBrowser browser = session.getBrowser();
if (browser.isIE() && browser.getBrowserMajorVersion() == 8) {
resource.padding(LONG_PADDING);
}
}
+
+ String requestToken = resource.getRequest().getParameter(
+ ApplicationConstants.CSRF_TOKEN_PARAMETER);
+ if (!VaadinService.isCsrfTokenValid(session, requestToken)) {
+ getLogger()
+ .log(Level.WARNING,
+ "Invalid CSRF token in new connection received from {0}",
+ resource.getRequest().getRemoteHost());
+ // Refresh on client side, create connection just for
+ // sending a message
+ AtmospherePushConnection connection = new AtmospherePushConnection(
+ ui);
+ connection.connect(resource);
+ sendRefresh(connection);
+ return;
+ }
+
resource.suspend();
AtmospherePushConnection connection = new AtmospherePushConnection(
@@ -122,19 +142,13 @@ public class PushHandler implements AtmosphereHandler {
getLogger().log(Level.SEVERE, "Error writing JSON to response",
e);
// Refresh on client side
- connection
- .sendMessage(VaadinService
- .createCriticalNotificationJSON(null, null,
- null, null));
+ sendRefresh(connection);
} catch (InvalidUIDLSecurityKeyException e) {
getLogger().log(Level.WARNING,
"Invalid security key received from {0}",
resource.getRequest().getRemoteHost());
// Refresh on client side
- connection
- .sendMessage(VaadinService
- .createCriticalNotificationJSON(null, null,
- null, null));
+ sendRefresh(connection);
}
}
};
@@ -314,6 +328,11 @@ public class PushHandler implements AtmosphereHandler {
public void destroy() {
}
+ private static void sendRefresh(AtmospherePushConnection connection) {
+ connection.sendMessage(VaadinService.createCriticalNotificationJSON(
+ null, null, null, null));
+ }
+
private static final Logger getLogger() {
return Logger.getLogger(PushHandler.class.getName());
}
diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
index 11de224e5e..64f8dfb223 100644
--- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java
+++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
@@ -41,6 +41,7 @@ import com.vaadin.server.ServerRpcManager;
import com.vaadin.server.ServerRpcManager.RpcInvocationException;
import com.vaadin.server.ServerRpcMethodInvocation;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
import com.vaadin.server.VariableOwner;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Connector;
@@ -108,29 +109,8 @@ public class ServerRpcHandler implements Serializable {
// Security: double cookie submission pattern unless disabled by
// property
- if (ui.getSession().getConfiguration().isXsrfProtectionEnabled()) {
- if (bursts.length == 1 && "init".equals(bursts[0])) {
- // init request; don't handle any variables, key sent in
- // response.
- // TODO This seems to be dead code
- request.setAttribute(
- LegacyCommunicationManager.WRITE_SECURITY_TOKEN_FLAG,
- true);
- return;
- } else {
- // ApplicationServlet has stored the security token in the
- // session; check that it matched the one sent in the UIDL
- String sessId = (String) ui
- .getSession()
- .getSession()
- .getAttribute(
- ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
-
- if (sessId == null || !sessId.equals(bursts[0])) {
- throw new InvalidUIDLSecurityKeyException("");
- }
- }
-
+ if (!VaadinService.isCsrfTokenValid(ui.getSession(), bursts[0])) {
+ throw new InvalidUIDLSecurityKeyException("");
}
handleBurst(ui, unescapeBurst(bursts[1]));
}
diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java
index efe11e02e9..7c8fc3a0d8 100644
--- a/server/src/com/vaadin/server/communication/UIInitHandler.java
+++ b/server/src/com/vaadin/server/communication/UIInitHandler.java
@@ -37,6 +37,7 @@ import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.ui.UI;
@@ -207,6 +208,13 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler {
ui.doInit(request, uiId.intValue());
+ PushMode pushMode = provider.getPushMode(event);
+ if (pushMode == null) {
+ pushMode = session.getService().getDeploymentConfiguration()
+ .getPushMode();
+ }
+ ui.setPushMode(pushMode);
+
session.addUI(ui);
// Remember if it should be remembered
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index 0ad2787cb6..adba9bd83e 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -543,10 +543,6 @@ public abstract class UI extends AbstractSingleComponentContainer implements
// Actual theme - used for finding CustomLayout templates
theme = request.getParameter("theme");
- PushMode pushMode = PushMode.valueOf(request.getParameter("v-pushMode")
- .toUpperCase());
- setPushMode(pushMode);
-
getPage().init(request);
// Call the init overridden by the application developer