瀏覽代碼

Update CookieCsrfTokenRepository docs to cookiHttpOnly=false

Currently CookieCsrfTokenRepository does not specify that the httpOnly
flag needs set to false. We should update the reference to include this
setting (and a comment about it) since it states that the settings will
work with AngularJS.

This commit updates the documentation and provides a convenience factory
method to create a CookieCsrfTokenRepository with cookiHttpOnly=false

Fixes gh-3865
Rob Winch 9 年之前
父節點
當前提交
d4218c70f1

+ 22 - 5
docs/manual/src/docs/asciidoc/index.adoc

@@ -3359,9 +3359,19 @@ You can configure `CookieCsrfTokenRepository` in XML using the following:
 	<!-- ... -->
 	<csrf token-repository-ref="tokenRepository"/>
 </http>
-<b:bean id="tokenRepository" class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"/>
+<b:bean id="tokenRepository"
+	class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
+	p:cookieHttpOnly="false"/>
 ----
 
+[NOTE]
+====
+The sample explicitly sets `cookieHttpOnly=false`.
+This is necessary to allow JavaScript (i.e. AngularJS) to read it.
+If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` to improve security.
+====
+
+
 You can configure `CookieCsrfTokenRepository` in Java Configuration using:
 
 [source,java]
@@ -3374,11 +3384,18 @@ public class WebSecurityConfig extends
 	protected void configure(HttpSecurity http) throws Exception {
 		http
 			.csrf()
-				.csrfTokenRepository(new CookieCsrfTokenRepository());
+				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
 	}
 }
 ----
 
+[NOTE]
+====
+The sample explicitly sets `cookieHttpOnly=false`.
+This is necessary to allow JavaScript (i.e. AngularJS) to read it.
+If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security.
+====
+
 
 [[csrf-caveats]]
 === CSRF Caveats
@@ -6594,9 +6611,9 @@ Spring Security provides `AuthenticationPrincipalArgumentResolver` which can aut
 [source,xml]
 ----
 <mvc:annotation-driven>
-    <mvc:argument-resolvers>
-        <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
-    </mvc:argument-resolvers>
+		<mvc:argument-resolvers>
+				<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
+		</mvc:argument-resolvers>
 </mvc:annotation-driven>
 ----
 

+ 14 - 1
web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java

@@ -31,7 +31,7 @@ import org.springframework.web.util.WebUtils;
 /**
  * A {@link CsrfTokenRepository} that persist the CSRF token in a cookie named
  * "XSRF-TOKEN" and reads from the header "X-XSRF-TOKEN" following the conventions of
- * AngularJS.
+ * AngularJS. When using with AngularJS be sure to use {@link #withHttpOnlyFalse()}.
  *
  * @author Rob Winch
  * @since 4.1
@@ -153,6 +153,19 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
 		return contextPath.length() > 0 ? contextPath : "/";
 	}
 
+	/**
+	 * Factory method to conveniently create an instance that has
+	 * {@link #setCookieHttpOnly(boolean)} set to false.
+	 *
+	 * @return and instance of CookieCsrfTokenRepository with
+	 * {@link #setCookieHttpOnly(boolean)} set to false
+	 */
+	public static CookieCsrfTokenRepository withHttpOnlyFalse() {
+		CookieCsrfTokenRepository result = new CookieCsrfTokenRepository();
+		result.setCookieHttpOnly(false);
+		return result;
+	}
+
 	private String createNewToken() {
 		return UUID.randomUUID().toString();
 	}

+ 12 - 0
web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java

@@ -138,6 +138,18 @@ public class CookieCsrfTokenRepositoryTests {
 		assertThat(tokenCookie.isHttpOnly()).isFalse();
 	}
 
+	@Test
+	public void saveTokenWithHttpOnlyFalse() {
+		this.repository = CookieCsrfTokenRepository.withHttpOnlyFalse();
+		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.isHttpOnly()).isFalse();
+	}
+
 	@Test
 	public void loadTokenNoCookiesNull() {
 		assertThat(this.repository.loadToken(this.request)).isNull();