This is the same as https://github.com/vaadin/framework/pull/12188, but also applied for the upload security key and the push id since both of those are also used to protect against cross-site attacks. In addition, documentation for the push id is clarified to point out its role. Cherry-picked from: https://github.com/vaadin/flow/pull/9896tags/8.13.0.alpha1
@@ -743,6 +743,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { | |||
*/ | |||
private final String csrfToken = UUID.randomUUID().toString(); | |||
/* | |||
* This token should be handled with care since it's used to protect against | |||
* cross-site attacks in addition to general identifier duty. | |||
*/ | |||
private final String pushId = UUID.randomUUID().toString(); | |||
/** |
@@ -23,6 +23,8 @@ import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.nio.charset.StandardCharsets; | |||
import java.security.MessageDigest; | |||
import com.vaadin.server.ClientConnector; | |||
import com.vaadin.server.NoInputStreamException; | |||
@@ -279,7 +281,10 @@ public class FileUploadHandler implements RequestHandler { | |||
streamVariable = uI.getConnectorTracker() | |||
.getStreamVariable(connectorId, variableName); | |||
String secKey = uI.getConnectorTracker().getSeckey(streamVariable); | |||
if (secKey == null || !secKey.equals(parts[3])) { | |||
String securityKey = parts[3]; | |||
if (secKey == null || !MessageDigest.isEqual( | |||
secKey.getBytes(StandardCharsets.UTF_8), | |||
securityKey.getBytes(StandardCharsets.UTF_8))) { | |||
return true; | |||
} | |||
@@ -18,6 +18,8 @@ package com.vaadin.server.communication; | |||
import java.io.IOException; | |||
import java.io.Reader; | |||
import java.nio.charset.StandardCharsets; | |||
import java.security.MessageDigest; | |||
import java.util.Collection; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
@@ -510,7 +512,9 @@ public class PushHandler { | |||
} | |||
/** | |||
* Checks whether a given push id matches the session's push id. | |||
* Checks whether a given push id matches the session's push id. The | |||
* comparison is done using a time-constant method since the push id is used | |||
* to protect against cross-site attacks. | |||
* | |||
* @param session | |||
* the vaadin session for which the check should be done | |||
@@ -522,7 +526,9 @@ public class PushHandler { | |||
String requestPushId) { | |||
String sessionPushId = session.getPushId(); | |||
if (requestPushId == null || !requestPushId.equals(sessionPushId)) { | |||
if (requestPushId == null || !MessageDigest.isEqual( | |||
requestPushId.getBytes(StandardCharsets.UTF_8), | |||
sessionPushId.getBytes(StandardCharsets.UTF_8))) { | |||
return false; | |||
} | |||
return true; |