1
0
mirror of synced 2026-09-12 12:15:13 +00:00

Ignore browserconfig.xml requests in default RequestCache

Legacy Internet Explorer 11 and pre-Chromium Edge automatically fetch
browserconfig.xml at the domain root to configure Windows pinned-site
tiles. It's still commonly generated by favicon-generator tooling even
though it's legacy, and is a background request unrelated to what the
user actually navigated to, so it shouldn't be able to become the URL
a user is redirected to after authenticating.

Closes gh-19693
This commit is contained in:
Robert Winch
2026-09-09 14:08:39 -05:00
parent d6363f2d3e
commit bf30738840
6 changed files with 44 additions and 3 deletions
@@ -185,7 +185,10 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
"/apple-touch-icon*.png",
// Chromium browsers fetch the web app manifest in the background to
// evaluate PWA installability
"/manifest.json", "/manifest.webmanifest" };
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
private RequestMatcher getIgnoredBackgroundRequestMatcher() {
List<RequestMatcher> matchers = new ArrayList<>();
@@ -186,6 +186,20 @@ public class RequestCacheConfigurerTests {
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@Test
public void getWhenBookmarkedUrlIsBrowserConfigXmlThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/browserconfig.xml"))
.andExpect(redirectedUrl("/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores browserconfig.xml
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
// SEC-2321
@Test
public void getWhenBookmarkedRequestIsApplicationJsonThenPostAuthenticationRedirectsToRoot() throws Exception {
@@ -171,7 +171,10 @@ public class CookieServerRequestCache implements ServerRequestCache {
"/apple-touch-icon*.png",
// Chromium browsers fetch the web app manifest in the background to
// evaluate PWA installability
"/manifest.json", "/manifest.webmanifest" };
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
ServerWebExchangeMatcher get = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/**");
@@ -171,7 +171,10 @@ public class WebSessionServerRequestCache implements ServerRequestCache {
"/apple-touch-icon*.png",
// Chromium browsers fetch the web app manifest in the background to
// evaluate PWA installability
"/manifest.json", "/manifest.webmanifest" };
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
ServerWebExchangeMatcher get = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/**");
@@ -122,6 +122,15 @@ public class CookieServerRequestCacheTests {
assertThat(cookies).isEmpty();
}
@Test
public void saveRequestWhenGetRequestBrowserConfigXmlThenNoCookie() {
MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/browserconfig.xml").accept(MediaType.TEXT_HTML));
this.cache.saveRequest(exchange).block();
MultiValueMap<String, ResponseCookie> cookies = exchange.getResponse().getCookies();
assertThat(cookies).isEmpty();
}
@Test
public void saveRequestWhenPostRequestThenNoCookie() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/secured/"));
@@ -113,6 +113,15 @@ public class WebSessionServerRequestCacheTests {
assertThat(saved).isNull();
}
@Test
public void saveRequestGetRequestWhenBrowserConfigXmlThenNotFound() {
MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/browserconfig.xml").accept(MediaType.TEXT_HTML));
this.cache.saveRequest(exchange).block();
URI saved = this.cache.getRedirectUri(exchange).block();
assertThat(saved).isNull();
}
@Test
public void saveRequestGetRequestWhenPostThenNotFound() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/secured/"));