This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new f4507c5ad0 Hardening: Use SecureRandom to generate Sec-WebSocket-Key
f4507c5ad0 is described below

commit f4507c5ad015ed0de268c0bae76917e885f42c4f
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Aug 25 11:03:02 2026 +0100

    Hardening: Use SecureRandom to generate Sec-WebSocket-Key
---
 java/org/apache/tomcat/websocket/Util.java                      | 6 +++---
 java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java  | 2 +-
 java/org/apache/tomcat/websocket/WsWebSocketContainer.java      | 5 +----
 test/org/apache/tomcat/websocket/TestUtil.java                  | 6 +++---
 test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java | 2 +-
 webapps/docs/changelog.xml                                      | 4 ++++
 6 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/Util.java 
b/java/org/apache/tomcat/websocket/Util.java
index c21dbc94b9..d9550ab423 100644
--- a/java/org/apache/tomcat/websocket/Util.java
+++ b/java/org/apache/tomcat/websocket/Util.java
@@ -137,7 +137,7 @@ public class Util {
     }
 
 
-    static byte[] generateMask() {
+    static byte[] generateRandomBytes(int len) {
         // SecureRandom is not thread-safe so need to make sure only one thread
         // uses it at a time. In theory, the pool could grow to the same size
         // as the number of request processing threads. In reality, it will be
@@ -156,8 +156,8 @@ public class Util {
             }
         }
 
-        // Generate the mask
-        byte[] result = new byte[4];
+        // Generate the random byte array
+        byte[] result = new byte[len];
         sr.nextBytes(result);
 
         // Put the SecureRandom back in the poll
diff --git a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java 
b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
index 1e3782063f..9dd87a6ea2 100644
--- a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
+++ b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
@@ -579,7 +579,7 @@ public abstract class WsRemoteEndpointImplBase implements 
RemoteEndpoint {
         byte[] mask;
 
         if (isMasked()) {
-            mask = Util.generateMask();
+            mask = Util.generateRandomBytes(4);
         } else {
             mask = null;
         }
diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java 
b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
index 4a80443c64..940b22d78c 100644
--- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
+++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
@@ -43,7 +43,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
@@ -91,7 +90,6 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
     }
 
     private static final StringManager sm = 
StringManager.getManager(WsWebSocketContainer.class);
-    private static final Random RANDOM = new Random();
     private static final byte[] CRLF = new byte[] { 13, 10 };
 
     private static final byte[] GET_BYTES = "GET 
".getBytes(StandardCharsets.ISO_8859_1);
@@ -784,8 +782,7 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
 
 
     private static String generateWsKeyValue() {
-        byte[] keyBytes = new byte[16];
-        RANDOM.nextBytes(keyBytes);
+        byte[] keyBytes = Util.generateRandomBytes(16);
         return Base64.getEncoder().encodeToString(keyBytes);
     }
 
diff --git a/test/org/apache/tomcat/websocket/TestUtil.java 
b/test/org/apache/tomcat/websocket/TestUtil.java
index e7a8c59e92..2dc2b7998c 100644
--- a/test/org/apache/tomcat/websocket/TestUtil.java
+++ b/test/org/apache/tomcat/websocket/TestUtil.java
@@ -31,9 +31,9 @@ import org.junit.Test;
 
 public class TestUtil {
 
-    // Used to init SecureRandom prior to running tests
-    public static void generateMask() {
-        Util.generateMask();
+    // Used to initialise SecureRandom prior to running tests
+    public static void initSecureRandom() {
+        Util.generateRandomBytes(1);
     }
 
     @Test
diff --git a/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java 
b/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java
index 739099df9a..16b1ddf5bf 100644
--- a/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java
+++ b/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java
@@ -45,7 +45,7 @@ public class TestPojoEndpointBase extends TomcatBaseTest {
 
     @Test
     public void testBug54716() throws Exception {
-        TestUtil.generateMask();
+        TestUtil.initSecureRandom();
         // Set up utility classes
         Bug54716 server = new Bug54716();
         SingletonConfigurator.setInstance(server);
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 571755d295..d51a2242b5 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -162,6 +162,10 @@
         Fix an exception when an automatic Pong response races with the
         closing of the WebSocket session. (moritzfl)
       </fix>
+      <fix>
+        Harden the WebSocket client and use a <code>SecureRandom</code> when
+        generating the <code>Sec-WebSocket-Key</code> header. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Web applications">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to