Skip to content

Commit d3fe49c

Browse files
committed
Fix possible ArrayIndexOutOfBoundsException in XorCsrfTokenRequestAttributeHandler and XorCsrfTokenUtils
1 parent 1825dcb commit d3fe49c

File tree

4 files changed

+24
-4
lines changed

4 files changed

+24
-4
lines changed

messaging/src/main/java/org/springframework/security/messaging/web/csrf/XorCsrfTokenUtils.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,16 @@ static String getTokenValue(String actualToken, String token) {
5656
System.arraycopy(actualBytes, randomBytesSize, xoredCsrf, 0, tokenSize);
5757

5858
byte[] csrfBytes = xorCsrf(randomBytes, xoredCsrf);
59-
return Utf8.decode(csrfBytes);
59+
return (csrfBytes != null) ? Utf8.decode(csrfBytes) : null;
6060
}
6161

62-
private static byte[] xorCsrf(byte[] randomBytes, byte[] csrfBytes) {
62+
static byte[] xorCsrf(byte[] randomBytes, byte[] csrfBytes) {
63+
if (csrfBytes.length < randomBytes.length) {
64+
return null;
65+
}
6366
int len = Math.min(randomBytes.length, csrfBytes.length);
6467
byte[] xoredCsrf = new byte[len];
65-
System.arraycopy(csrfBytes, 0, xoredCsrf, 0, csrfBytes.length);
68+
System.arraycopy(csrfBytes, 0, xoredCsrf, 0, len);
6669
for (int i = 0; i < len; i++) {
6770
xoredCsrf[i] ^= randomBytes[i];
6871
}

messaging/src/test/java/org/springframework/security/messaging/web/csrf/XorCsrfChannelInterceptorTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.security.web.csrf.MissingCsrfTokenException;
3333

3434
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
35+
import static org.assertj.core.api.Assertions.assertThatNoException;
3536
import static org.mockito.Mockito.mock;
3637

3738
/**
@@ -141,6 +142,14 @@ public void preSendWhenUnsubscribeThenIgnores() {
141142
this.interceptor.preSend(message(), this.channel);
142143
}
143144

145+
@Test
146+
public void preSendWhenCsrfBytesIsLongerThanRandomBytesThenArrayIndexOutOfBoundsExceptionWillNotBeThrown() {
147+
this.messageHeaders.setNativeHeader(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE);
148+
DefaultCsrfToken token = new DefaultCsrfToken("header", "param", "tokenl");
149+
this.messageHeaders.getSessionAttributes().put(CsrfToken.class.getName(), token);
150+
assertThatNoException().isThrownBy(() -> this.interceptor.preSend(message(), this.channel));
151+
}
152+
144153
private Message<String> message() {
145154
return MessageBuilder.withPayload("message").copyHeaders(this.messageHeaders.toMap()).build();
146155
}

web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ private static byte[] xorCsrf(byte[] randomBytes, byte[] csrfBytes) {
119119
}
120120
int len = Math.min(randomBytes.length, csrfBytes.length);
121121
byte[] xoredCsrf = new byte[len];
122-
System.arraycopy(csrfBytes, 0, xoredCsrf, 0, csrfBytes.length);
122+
System.arraycopy(csrfBytes, 0, xoredCsrf, 0, len);
123123
for (int i = 0; i < len; i++) {
124124
xoredCsrf[i] ^= randomBytes[i];
125125
}

web/src/test/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandlerTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static org.assertj.core.api.Assertions.assertThat;
3131
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3232
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
33+
import static org.assertj.core.api.Assertions.assertThatNoException;
3334
import static org.mockito.ArgumentMatchers.any;
3435
import static org.mockito.BDDMockito.willAnswer;
3536
import static org.mockito.Mockito.mock;
@@ -216,6 +217,13 @@ public void resolveCsrfTokenIsInvalidThenReturnsNull() {
216217
assertThat(tokenValue).isNull();
217218
}
218219

220+
@Test
221+
public void resolveCsrfTokenValueWhenCsrfBytesIsLongerThanRandomBytesThenArrayIndexOutOfBoundsExceptionWillNotBeThrown() {
222+
this.request.setParameter(this.token.getParameterName(), XOR_CSRF_TOKEN_VALUE);
223+
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "ABCDE");
224+
assertThatNoException().isThrownBy(() -> { this.handler.resolveCsrfTokenValue(this.request, csrfToken); });
225+
}
226+
219227
private static Answer<Void> fillByteArray() {
220228
return (invocation) -> {
221229
byte[] bytes = invocation.getArgument(0);

0 commit comments

Comments
 (0)