From e113bd3c01f32a245dbd44b8329d2e33361a9c06 Mon Sep 17 00:00:00 2001 From: michal Date: Mon, 22 Jun 2020 22:29:14 +0200 Subject: [PATCH] issue 5414 - configurable secure flag in CookieCsrfTokenRepository While using the request's "isSecure" flag is a reasonable default, when webapps sit behind firewalls, sometimes the firewall does the SSL, and the traffic between the firewall and the app is plain HTTP (not HTTPS). In this case the "isSecure" flag on the request is always false, but we still want th XSRF-TOKEN cookie to be secure (the firewall forwards all cookies to the app, and the browser sends the secure cookie to the firewall). It would be nice if we could configure the desired value for the secure flag of the cookie, just like we can configure the value for the httpOnly flag of the cookie. --- .../web/csrf/CookieCsrfTokenRepository.java | 23 +++++++++++++++- .../csrf/CookieCsrfTokenRepositoryTests.java | 27 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java index 1c77c9bbad..1ffc01a606 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java @@ -18,6 +18,7 @@ package org.springframework.security.web.csrf; import java.util.UUID; +import javax.servlet.ServletRequest; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -53,6 +54,8 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { private String cookieDomain; + private Boolean secure; + public CookieCsrfTokenRepository() { } @@ -67,7 +70,12 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { HttpServletResponse response) { String tokenValue = token == null ? "" : token.getToken(); Cookie cookie = new Cookie(this.cookieName, tokenValue); - cookie.setSecure(request.isSecure()); + if (secure == null) { + cookie.setSecure(request.isSecure()); + } else { + cookie.setSecure(secure); + } + if (this.cookiePath != null && !this.cookiePath.isEmpty()) { cookie.setPath(this.cookiePath); } else { @@ -195,4 +203,17 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { this.cookieDomain = cookieDomain; } + /** + * Sets secure flag of the cookie that the expected CSRF token is saved to and read from. + * By default secure flag depends on {@link ServletRequest#isSecure()} + * + * @since 5.4 + * @param secure the secure flag of the cookie that the expected CSRF token is saved to + * and read from + */ + public void setSecure(Boolean secure) { + this.secure = secure; + } + + } diff --git a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java index 7ec2fdb389..7f40afde2e 100644 --- a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java @@ -98,6 +98,33 @@ public class CookieCsrfTokenRepositoryTests { assertThat(tokenCookie.getSecure()).isTrue(); } + @Test + public void saveTokenSecureFlagTrue() { + this.request.setSecure(false); + this.repository.setSecure(Boolean.TRUE); + CsrfToken token = this.repository.generateToken(this.request); + this.repository.saveToken(token, this.request, this.response); + + Cookie tokenCookie = this.response + .getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); + + assertThat(tokenCookie.getSecure()).isTrue(); + } + + @Test + public void saveTokenSecureFlagFalse() { + this.request.setSecure(true); + this.repository.setSecure(Boolean.FALSE); + CsrfToken token = this.repository.generateToken(this.request); + this.repository.saveToken(token, this.request, this.response); + + Cookie tokenCookie = this.response + .getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); + + assertThat(tokenCookie.getSecure()).isFalse(); + } + + @Test public void saveTokenNull() { this.request.setSecure(true);