diff --git a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java index 021ae0051d12..35eade1891f6 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java @@ -75,6 +75,7 @@ private ResponseCookie(String name, @Nullable String value, Duration maxAge, @Nu Rfc6265Utils.validateCookieValue(value); Rfc6265Utils.validateDomain(domain); Rfc6265Utils.validatePath(path); + Rfc6265Utils.validateSameSite(sameSite); } @@ -433,6 +434,18 @@ public static void validatePath(@Nullable String path) { } } } + + public static void validateSameSite(@Nullable String sameSite) { + if (sameSite == null) { + return; + } + for (int i = 0; i < sameSite.length(); i++) { + char c = sameSite.charAt(i); + if (c < 0x20 || c > 0x7E || c == ';') { + throw new IllegalArgumentException(sameSite + ": Invalid cookie SameSite char '" + c + "'"); + } + } + } } diff --git a/spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java b/spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java index d145f3f92a8c..cbacb1d214a5 100644 --- a/spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java +++ b/spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java @@ -82,6 +82,17 @@ void domainChecks() { .hasMessageContaining("invalid cookie domain char")); } + @Test + void sameSiteChecks() { + + Arrays.asList("Strict", "Lax", "None") + .forEach(sameSite -> ResponseCookie.from("n", "v").sameSite(sameSite).build()); + + Arrays.asList("Lax\r\nSet-Cookie: x=y", "Lax\n", "La;x", "Lax\t", "Lax\u0005") + .forEach(sameSite -> assertThatThrownBy(() -> ResponseCookie.from("n", "v").sameSite(sameSite).build()) + .hasMessageContaining("Invalid cookie SameSite char")); + } + @Test // gh-24663 void domainWithEmptyDoubleQuotes() {