From a46c97bd7936ea8793618bb54ce19ac32c61f71d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 25 Apr 2013 12:45:45 +0300 Subject: 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 --- .../vaadin/client/ApplicationConfiguration.java | 14 ----- .../com/vaadin/client/ApplicationConnection.java | 61 ++++++---------------- .../communication/AtmospherePushConnection.java | 2 + 3 files changed, 18 insertions(+), 59 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index e1f460ff48..adf5e1de9d 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -46,7 +46,6 @@ import com.vaadin.client.metadata.NoDataException; import com.vaadin.client.metadata.TypeData; import com.vaadin.client.ui.UnknownComponentConnector; import com.vaadin.shared.ApplicationConstants; -import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.ui.UIConstants; public class ApplicationConfiguration implements EntryPoint { @@ -212,7 +211,6 @@ public class ApplicationConfiguration implements EntryPoint { private ErrorMessage authorizationError; private ErrorMessage sessionExpiredError; private int heartbeatInterval; - private PushMode pushMode; private HashMap unknownComponents; @@ -325,10 +323,6 @@ public class ApplicationConfiguration implements EntryPoint { return heartbeatInterval; } - public PushMode getPushMode() { - return pushMode; - } - public JavaScriptObject getVersionInfoJSObject() { return getJsoConfiguration(id).getVersionInfoJSObject(); } @@ -382,14 +376,6 @@ public class ApplicationConfiguration implements EntryPoint { heartbeatInterval = jsoConfiguration .getConfigInteger("heartbeatInterval"); - String pushMode = jsoConfiguration.getConfigString("pushMode"); - if (pushMode != null) { - this.pushMode = Enum - .valueOf(PushMode.class, pushMode.toUpperCase()); - } else { - this.pushMode = PushMode.DISABLED; - } - communicationError = jsoConfiguration.getConfigError("comErrMsg"); authorizationError = jsoConfiguration.getConfigError("authErrMsg"); sessionExpiredError = jsoConfiguration.getConfigError("sessExpMsg"); diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index dc8dbcaf43..85cf0f0b46 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -156,8 +156,8 @@ public class ApplicationConnection { */ public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh"; - // will hold the UIDL security key (for XSS protection) once received - private String uidlSecurityKey = "init"; + // will hold the CSRF token once received + private String csrfToken = "init"; private final HashMap resourcesMap = new HashMap(); @@ -182,19 +182,6 @@ public class ApplicationConnection { protected boolean applicationRunning = false; - /** - * Keep track of whether the initialization JSON has been handled. We should - * not process any push messages until the initial JSON has been processed. - */ - private boolean initJsonHandled = false; - - /** - * Keep track of any push messages that arrive before - * {@link #initJsonHandled} is set to true. - */ - private JsArrayString incommingPushMessageQueue = JsArrayString - .createArray().cast(); - private boolean hasActiveRequest = false; /** @@ -455,8 +442,6 @@ public class ApplicationConnection { scheduleHeartbeat(); - setPushEnabled(getConfiguration().getPushMode().isEnabled()); - Window.addWindowClosingHandler(new ClosingHandler() { @Override public void onWindowClosing(ClosingEvent event) { @@ -715,7 +700,7 @@ public class ApplicationConnection { final String extraParams) { startRequest(); // Security: double cookie submission pattern - final String payload = uidlSecurityKey + VAR_BURST_SEPARATOR + final String payload = getCsrfToken() + VAR_BURST_SEPARATOR + requestData; VConsole.log("Making UIDL Request with params: " + payload); String uri = translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX @@ -1127,25 +1112,6 @@ public class ApplicationConnection { runPostRequestHooks(configuration.getRootPanelId()); } - if (!initJsonHandled) { - /* - * Assume that the first request that is fully handled is the one - * with the initialization data. - */ - initJsonHandled = true; - - int queueLength = incommingPushMessageQueue.length(); - if (queueLength > 0) { - VConsole.log("Init handled, processing " + queueLength - + " enqueued messages"); - for (int i = 0; i < queueLength; i++) { - handlePushMessage(incommingPushMessageQueue.get(i)); - } - incommingPushMessageQueue.setLength(0); - } - - } - // deferring to avoid flickering Scheduler.get().scheduleDeferred(new Command() { @Override @@ -1315,7 +1281,7 @@ public class ApplicationConnection { // Get security key if (json.containsKey(ApplicationConstants.UIDL_SECURITY_TOKEN_ID)) { - uidlSecurityKey = json + csrfToken = json .getString(ApplicationConstants.UIDL_SECURITY_TOKEN_ID); } VConsole.log(" * Handling resources from server"); @@ -3034,7 +3000,17 @@ public class ApplicationConnection { private ConnectorMap connectorMap = GWT.create(ConnectorMap.class); protected String getUidlSecurityKey() { - return uidlSecurityKey; + return getCsrfToken(); + } + + /** + * Gets the token (aka double submit cookie) that the server uses to protect + * against Cross Site Request Forgery attacks. + * + * @return the CSRF token string + */ + public String getCsrfToken() { + return csrfToken; } /** @@ -3443,11 +3419,6 @@ public class ApplicationConnection { } public void handlePushMessage(String message) { - if (initJsonHandled) { - handleJSONText(message, 200); - } else { - VConsole.log("Enqueuing push message has init has not yet been handled"); - incommingPushMessageQueue.push(message); - } + handleJSONText(message, 200); } } diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index ef5fc56347..bd666cb464 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -113,6 +113,8 @@ public class AtmospherePushConnection implements PushConnection { + ApplicationConstants.PUSH_PATH + '/'); String extraParams = UIConstants.UI_ID_PARAMETER + "=" + connection.getConfiguration().getUIId(); + extraParams += "&" + ApplicationConstants.CSRF_TOKEN_PARAMETER + "=" + + connection.getCsrfToken(); // uri is needed to identify the right connection when closing uri = ApplicationConnection.addGetParameters(baseUrl, extraParams); -- cgit v1.2.3