Skip to content

Commit 4a1cd90

Browse files
authored
Merge branch 'main' into feat/webflux-performance
2 parents 8f00991 + 674b462 commit 4a1cd90

File tree

12 files changed

+363
-33
lines changed

12 files changed

+363
-33
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414

1515
- Fix timestamps of slow and frozen frames for profiles ([#2584](https://github.com/getsentry/sentry-java/pull/2584))
1616
- Deprecate reportFullDisplayed in favor of reportFullyDisplayed ([#2585](https://github.com/getsentry/sentry-java/pull/2585))
17+
- Filter out session cookies sent by Spring and Spring Boot integrations ([#2593](https://github.com/getsentry/sentry-java/pull/2593))
18+
- We filter out some common cookies like JSESSIONID
19+
- We also read the value from `server.servlet.session.cookie.name` and filter it out
1720
- No longer send event / transaction to Sentry if `beforeSend` / `beforeSendTransaction` throws ([#2591](https://github.com/getsentry/sentry-java/pull/2591))
1821
- Add version to sentryClientName used in auth header ([#2596](https://github.com/getsentry/sentry-java/pull/2596))
22+
- Keep integration names from being obfuscated ([#2599](https://github.com/getsentry/sentry-java/pull/2599))
1923

2024
### Dependencies
2125

sentry-android-core/proguard-rules.pro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,7 @@
2929
# https://developer.android.com/studio/build/shrink-code#decode-stack-trace
3030
-keepattributes LineNumberTable,SourceFile
3131

32+
# Keep Classnames for integrations
33+
-keepnames class * implements io.sentry.IntegrationName
34+
3235
##---------------End: proguard configuration for android-core ----------

sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryRequestResolver.java

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
import com.jakewharton.nopen.annotation.Open;
44
import io.sentry.IHub;
5+
import io.sentry.SentryLevel;
56
import io.sentry.protocol.Request;
67
import io.sentry.util.HttpUtils;
78
import io.sentry.util.Objects;
89
import io.sentry.util.UrlUtils;
10+
import jakarta.servlet.ServletContext;
11+
import jakarta.servlet.SessionCookieConfig;
912
import jakarta.servlet.http.HttpServletRequest;
13+
import java.util.Arrays;
1014
import java.util.Collections;
11-
import java.util.Enumeration;
1215
import java.util.HashMap;
16+
import java.util.List;
1317
import java.util.Map;
1418
import org.jetbrains.annotations.NotNull;
1519
import org.jetbrains.annotations.Nullable;
1620

1721
@Open
1822
public class SentryRequestResolver {
1923
private final @NotNull IHub hub;
24+
private volatile @Nullable List<String> extraSecurityCookies;
2025

2126
public SentryRequestResolver(final @NotNull IHub hub) {
2227
this.hub = Objects.requireNonNull(hub, "options is required");
@@ -31,27 +36,73 @@ public SentryRequestResolver(final @NotNull IHub hub) {
3136
UrlUtils.parse(httpRequest.getRequestURL().toString());
3237
urlDetails.applyToRequest(sentryRequest);
3338
sentryRequest.setQueryString(httpRequest.getQueryString());
34-
sentryRequest.setHeaders(resolveHeadersMap(httpRequest));
39+
final @NotNull List<String> additionalSecurityCookieNames =
40+
extractSecurityCookieNamesOrUseCached(httpRequest);
41+
sentryRequest.setHeaders(resolveHeadersMap(httpRequest, additionalSecurityCookieNames));
3542

3643
if (hub.getOptions().isSendDefaultPii()) {
37-
sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie")));
44+
String cookieName = HttpUtils.COOKIE_HEADER_NAME;
45+
final @Nullable List<String> filteredHeaders =
46+
HttpUtils.filterOutSecurityCookiesFromHeader(
47+
httpRequest.getHeaders(cookieName), cookieName, additionalSecurityCookieNames);
48+
sentryRequest.setCookies(toString(filteredHeaders));
3849
}
3950
return sentryRequest;
4051
}
4152

4253
@NotNull
43-
Map<String, String> resolveHeadersMap(final @NotNull HttpServletRequest request) {
54+
Map<String, String> resolveHeadersMap(
55+
final @NotNull HttpServletRequest request,
56+
final @NotNull List<String> additionalSecurityCookieNames) {
4457
final Map<String, String> headersMap = new HashMap<>();
4558
for (String headerName : Collections.list(request.getHeaderNames())) {
4659
// do not copy personal information identifiable headers
4760
if (hub.getOptions().isSendDefaultPii() || !HttpUtils.containsSensitiveHeader(headerName)) {
48-
headersMap.put(headerName, toString(request.getHeaders(headerName)));
61+
final @Nullable List<String> filteredHeaders =
62+
HttpUtils.filterOutSecurityCookiesFromHeader(
63+
request.getHeaders(headerName), headerName, additionalSecurityCookieNames);
64+
headersMap.put(headerName, toString(filteredHeaders));
4965
}
5066
}
5167
return headersMap;
5268
}
5369

54-
private static @Nullable String toString(final @Nullable Enumeration<String> enumeration) {
55-
return enumeration != null ? String.join(",", Collections.list(enumeration)) : null;
70+
private List<String> extractSecurityCookieNamesOrUseCached(
71+
final @NotNull HttpServletRequest httpRequest) {
72+
if (extraSecurityCookies == null) {
73+
synchronized (SentryRequestResolver.class) {
74+
if (extraSecurityCookies == null) {
75+
extraSecurityCookies = extractSecurityCookieNames(httpRequest);
76+
}
77+
}
78+
}
79+
80+
return extraSecurityCookies;
81+
}
82+
83+
private List<String> extractSecurityCookieNames(final @NotNull HttpServletRequest httpRequest) {
84+
try {
85+
final @Nullable ServletContext servletContext = httpRequest.getServletContext();
86+
if (servletContext != null) {
87+
final @Nullable SessionCookieConfig sessionCookieConfig =
88+
servletContext.getSessionCookieConfig();
89+
if (sessionCookieConfig != null) {
90+
final @Nullable String cookieName = sessionCookieConfig.getName();
91+
if (cookieName != null) {
92+
return Arrays.asList(cookieName);
93+
}
94+
}
95+
}
96+
} catch (Throwable t) {
97+
hub.getOptions()
98+
.getLogger()
99+
.log(SentryLevel.WARNING, "Failed to extract session cookie name from request.", t);
100+
}
101+
102+
return Collections.emptyList();
103+
}
104+
105+
private static @Nullable String toString(final @Nullable List<String> list) {
106+
return list != null ? String.join(",", list) : null;
56107
}
57108
}

sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/webflux/SentryRequestResolver.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.sentry.util.Objects;
88
import io.sentry.util.UrlUtils;
99
import java.net.URI;
10+
import java.util.Collections;
1011
import java.util.HashMap;
1112
import java.util.List;
1213
import java.util.Map;
@@ -36,7 +37,11 @@ public SentryRequestResolver(final @NotNull IHub hub) {
3637
sentryRequest.setHeaders(resolveHeadersMap(httpRequest.getHeaders()));
3738

3839
if (hub.getOptions().isSendDefaultPii()) {
39-
sentryRequest.setCookies(toString(httpRequest.getHeaders().get("Cookies")));
40+
String headerName = HttpUtils.COOKIE_HEADER_NAME;
41+
sentryRequest.setCookies(
42+
toString(
43+
HttpUtils.filterOutSecurityCookiesFromHeader(
44+
httpRequest.getHeaders().get(headerName), headerName, Collections.emptyList())));
4045
}
4146
return sentryRequest;
4247
}
@@ -46,9 +51,13 @@ Map<String, String> resolveHeadersMap(final HttpHeaders request) {
4651
final Map<String, String> headersMap = new HashMap<>();
4752
for (Map.Entry<String, List<String>> entry : request.entrySet()) {
4853
// do not copy personal information identifiable headers
49-
if (hub.getOptions().isSendDefaultPii()
50-
|| !HttpUtils.containsSensitiveHeader(entry.getKey())) {
51-
headersMap.put(entry.getKey(), toString(entry.getValue()));
54+
String headerName = entry.getKey();
55+
if (hub.getOptions().isSendDefaultPii() || !HttpUtils.containsSensitiveHeader(headerName)) {
56+
headersMap.put(
57+
headerName,
58+
toString(
59+
HttpUtils.filterOutSecurityCookiesFromHeader(
60+
entry.getValue(), headerName, Collections.emptyList())));
5261
}
5362
}
5463
return headersMap;

sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/SentrySpringFilterTest.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.sentry.SentryOptions.RequestSize.MEDIUM
1010
import io.sentry.SentryOptions.RequestSize.NONE
1111
import io.sentry.SentryOptions.RequestSize.SMALL
1212
import jakarta.servlet.FilterChain
13+
import jakarta.servlet.ServletContext
1314
import jakarta.servlet.http.HttpServletRequest
1415
import org.assertj.core.api.Assertions
1516
import org.mockito.kotlin.any
@@ -150,24 +151,27 @@ class SentrySpringFilterTest {
150151
}
151152

152153
@Test
153-
fun `when sendDefaultPii is set to true, attaches cookies information to Scope request`() {
154+
fun `when sendDefaultPii is set to true, attaches filtered cookies to Scope request`() {
154155
val sentryOptions = SentryOptions().apply {
155156
isSendDefaultPii = true
156157
}
157158

158159
val listener = fixture.getSut(
159160
request = MockMvcRequestBuilders
160161
.get(URI.create("http://example.com?param1=xyz"))
161-
.header("Cookie", "name=value")
162-
.header("Cookie", "name2=value2")
163-
.buildRequest(MockServletContext()),
162+
.header("Cookie", "name=value; JSESSIONID=123; mysessioncookiename=789")
163+
.header("Cookie", "name2=value2; SID=456")
164+
.buildRequest(servletContextWithCustomCookieName("mysessioncookiename")),
164165
options = sentryOptions
165166
)
166167

167168
listener.doFilter(fixture.request, fixture.response, fixture.chain)
168169

169170
assertNotNull(fixture.scope.request) {
170-
assertEquals("name=value,name2=value2", it.cookies)
171+
val expectedCookieString =
172+
"name=value; JSESSIONID=[Filtered]; mysessioncookiename=[Filtered],name2=value2; SID=[Filtered]"
173+
assertEquals(expectedCookieString, it.cookies)
174+
assertEquals(expectedCookieString, it.headers!!["Cookie"])
171175
}
172176
}
173177

@@ -269,4 +273,8 @@ class SentrySpringFilterTest {
269273
}
270274
}
271275
}
276+
277+
private fun servletContextWithCustomCookieName(name: String): ServletContext {
278+
return MockServletContext().also { it.sessionCookieConfig.name = name }
279+
}
272280
}

sentry-spring/src/main/java/io/sentry/spring/SentryRequestResolver.java

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
import com.jakewharton.nopen.annotation.Open;
44
import io.sentry.IHub;
5+
import io.sentry.SentryLevel;
56
import io.sentry.protocol.Request;
67
import io.sentry.util.HttpUtils;
78
import io.sentry.util.Objects;
89
import io.sentry.util.UrlUtils;
10+
import java.util.Arrays;
911
import java.util.Collections;
10-
import java.util.Enumeration;
1112
import java.util.HashMap;
13+
import java.util.List;
1214
import java.util.Map;
15+
import javax.servlet.ServletContext;
16+
import javax.servlet.SessionCookieConfig;
1317
import javax.servlet.http.HttpServletRequest;
1418
import org.jetbrains.annotations.NotNull;
1519
import org.jetbrains.annotations.Nullable;
1620

1721
@Open
1822
public class SentryRequestResolver {
1923
private final @NotNull IHub hub;
24+
private volatile @Nullable List<String> extraSecurityCookies;
2025

2126
public SentryRequestResolver(final @NotNull IHub hub) {
2227
this.hub = Objects.requireNonNull(hub, "options is required");
@@ -31,27 +36,73 @@ public SentryRequestResolver(final @NotNull IHub hub) {
3136
UrlUtils.parse(httpRequest.getRequestURL().toString());
3237
urlDetails.applyToRequest(sentryRequest);
3338
sentryRequest.setQueryString(httpRequest.getQueryString());
34-
sentryRequest.setHeaders(resolveHeadersMap(httpRequest));
39+
final @NotNull List<String> additionalSecurityCookieNames =
40+
extractSecurityCookieNamesOrUseCached(httpRequest);
41+
sentryRequest.setHeaders(resolveHeadersMap(httpRequest, additionalSecurityCookieNames));
3542

3643
if (hub.getOptions().isSendDefaultPii()) {
37-
sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie")));
44+
String cookieName = HttpUtils.COOKIE_HEADER_NAME;
45+
final @Nullable List<String> filteredHeaders =
46+
HttpUtils.filterOutSecurityCookiesFromHeader(
47+
httpRequest.getHeaders(cookieName), cookieName, additionalSecurityCookieNames);
48+
sentryRequest.setCookies(toString(filteredHeaders));
3849
}
3950
return sentryRequest;
4051
}
4152

4253
@NotNull
43-
Map<String, String> resolveHeadersMap(final @NotNull HttpServletRequest request) {
54+
Map<String, String> resolveHeadersMap(
55+
final @NotNull HttpServletRequest request,
56+
final @NotNull List<String> additionalSecurityCookieNames) {
4457
final Map<String, String> headersMap = new HashMap<>();
4558
for (String headerName : Collections.list(request.getHeaderNames())) {
4659
// do not copy personal information identifiable headers
4760
if (hub.getOptions().isSendDefaultPii() || !HttpUtils.containsSensitiveHeader(headerName)) {
48-
headersMap.put(headerName, toString(request.getHeaders(headerName)));
61+
final @Nullable List<String> filteredHeaders =
62+
HttpUtils.filterOutSecurityCookiesFromHeader(
63+
request.getHeaders(headerName), headerName, additionalSecurityCookieNames);
64+
headersMap.put(headerName, toString(filteredHeaders));
4965
}
5066
}
5167
return headersMap;
5268
}
5369

54-
private static @Nullable String toString(final @Nullable Enumeration<String> enumeration) {
55-
return enumeration != null ? String.join(",", Collections.list(enumeration)) : null;
70+
private List<String> extractSecurityCookieNamesOrUseCached(
71+
final @NotNull HttpServletRequest httpRequest) {
72+
if (extraSecurityCookies == null) {
73+
synchronized (SentryRequestResolver.class) {
74+
if (extraSecurityCookies == null) {
75+
extraSecurityCookies = extractSecurityCookieNames(httpRequest);
76+
}
77+
}
78+
}
79+
80+
return extraSecurityCookies;
81+
}
82+
83+
private List<String> extractSecurityCookieNames(final @NotNull HttpServletRequest httpRequest) {
84+
try {
85+
final @Nullable ServletContext servletContext = httpRequest.getServletContext();
86+
if (servletContext != null) {
87+
final @Nullable SessionCookieConfig sessionCookieConfig =
88+
servletContext.getSessionCookieConfig();
89+
if (sessionCookieConfig != null) {
90+
final @Nullable String cookieName = sessionCookieConfig.getName();
91+
if (cookieName != null) {
92+
return Arrays.asList(cookieName);
93+
}
94+
}
95+
}
96+
} catch (Throwable t) {
97+
hub.getOptions()
98+
.getLogger()
99+
.log(SentryLevel.WARNING, "Failed to extract session cookie name from request.", t);
100+
}
101+
102+
return Collections.emptyList();
103+
}
104+
105+
private static @Nullable String toString(final @Nullable List<String> list) {
106+
return list != null ? String.join(",", list) : null;
56107
}
57108
}

sentry-spring/src/main/java/io/sentry/spring/webflux/SentryRequestResolver.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.sentry.util.Objects;
88
import io.sentry.util.UrlUtils;
99
import java.net.URI;
10+
import java.util.Collections;
1011
import java.util.HashMap;
1112
import java.util.List;
1213
import java.util.Map;
@@ -36,7 +37,11 @@ public SentryRequestResolver(final @NotNull IHub hub) {
3637
sentryRequest.setHeaders(resolveHeadersMap(httpRequest.getHeaders()));
3738

3839
if (hub.getOptions().isSendDefaultPii()) {
39-
sentryRequest.setCookies(toString(httpRequest.getHeaders().get("Cookies")));
40+
String headerName = HttpUtils.COOKIE_HEADER_NAME;
41+
sentryRequest.setCookies(
42+
toString(
43+
HttpUtils.filterOutSecurityCookiesFromHeader(
44+
httpRequest.getHeaders().get(headerName), headerName, Collections.emptyList())));
4045
}
4146
return sentryRequest;
4247
}
@@ -46,9 +51,13 @@ Map<String, String> resolveHeadersMap(final HttpHeaders request) {
4651
final Map<String, String> headersMap = new HashMap<>();
4752
for (Map.Entry<String, List<String>> entry : request.entrySet()) {
4853
// do not copy personal information identifiable headers
49-
if (hub.getOptions().isSendDefaultPii()
50-
|| !HttpUtils.containsSensitiveHeader(entry.getKey())) {
51-
headersMap.put(entry.getKey(), toString(entry.getValue()));
54+
String headerName = entry.getKey();
55+
if (hub.getOptions().isSendDefaultPii() || !HttpUtils.containsSensitiveHeader(headerName)) {
56+
headersMap.put(
57+
headerName,
58+
toString(
59+
HttpUtils.filterOutSecurityCookiesFromHeader(
60+
entry.getValue(), headerName, Collections.emptyList())));
5261
}
5362
}
5463
return headersMap;

0 commit comments

Comments
 (0)