1
0
mirror of synced 2026-08-02 08:17:03 +00:00

SEC-2276: Delay saving CsrfToken until token is accessed

This also removed the CsrfToken from the response headers to prevent the
token from being saved. If user's wish to return the CsrfToken in the
response headers, they should use the CsrfToken found on the request.
This commit is contained in:
Rob Winch
2013-08-24 23:28:15 -05:00
parent c131fb6379
commit 48283ec004
14 changed files with 355 additions and 159 deletions
@@ -36,6 +36,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.security.web.csrf.CsrfToken
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
import spock.lang.AutoCleanup
@@ -69,7 +70,7 @@ abstract class BaseSpringSpec extends Specification {
}
def setupCsrf(csrfTokenValue="BaseSpringSpec_CSRFTOKEN") {
csrfToken = new CsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request,response)
request.setParameter(csrfToken.parameterName, csrfToken.token)
}
@@ -79,8 +79,7 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache,no-store,max-age=0,must-revalidate',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block',
'X-CSRF-TOKEN' : csrfToken.token]
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
@@ -49,8 +49,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache,no-store,max-age=0,must-revalidate',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block',
'X-CSRF-TOKEN' : csrfToken.token]
'X-XSS-Protection' : '1; mode=block']
}
@Configuration
@@ -70,8 +69,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Cache-Control': 'no-cache,no-store,max-age=0,must-revalidate',
'Pragma':'no-cache',
'X-CSRF-TOKEN' : csrfToken.token]
'Pragma':'no-cache']
}
@Configuration
@@ -91,8 +89,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
}
@Configuration
@@ -111,8 +108,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=15768000',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['Strict-Transport-Security': 'max-age=15768000']
}
@Configuration
@@ -133,8 +129,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Frame-Options': 'SAMEORIGIN',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['X-Frame-Options': 'SAMEORIGIN']
}
@Configuration
@@ -156,8 +151,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Frame-Options': 'ALLOW-FROM https://example.com',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['X-Frame-Options': 'ALLOW-FROM https://example.com']
}
@@ -178,8 +172,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-XSS-Protection': '1; mode=block',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['X-XSS-Protection': '1; mode=block']
}
@Configuration
@@ -199,8 +192,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-XSS-Protection': '1',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['X-XSS-Protection': '1']
}
@Configuration
@@ -220,8 +212,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options': 'nosniff',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['X-Content-Type-Options': 'nosniff']
}
@Configuration
@@ -243,8 +234,7 @@ public class NamespaceHttpHeadersTests extends BaseSpringSpec {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['customHeaderName': 'customHeaderValue',
'X-CSRF-TOKEN' : csrfToken.token]
responseHeaders == ['customHeaderName': 'customHeaderValue']
}
@Configuration
@@ -29,6 +29,7 @@ import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfFilter
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor
import org.springframework.security.web.util.RequestMatcher
@@ -113,7 +114,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
mockBean(CsrfTokenRepository,'repo')
createAppContext()
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
CsrfToken token = new CsrfToken("X-CSRF-TOKEN","_csrf", "abc")
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.servletPath = "/some-url"
@@ -147,7 +148,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
mockBean(CsrfTokenRepository,'repo')
createAppContext()
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
CsrfToken token = new CsrfToken("X-CSRF-TOKEN","_csrf", "abc")
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.servletPath = "/some-url"
@@ -200,7 +201,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
mockBean(CsrfTokenRepository,'repo')
createAppContext()
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
CsrfToken token = new CsrfToken("X-CSRF-TOKEN","_csrf", "abc")
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.method = "POST"
@@ -223,7 +224,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
mockBean(CsrfTokenRepository,'repo')
createAppContext()
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
CsrfToken token = new CsrfToken("X-CSRF-TOKEN","_csrf", "abc")
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.method = "POST"
@@ -244,7 +245,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
mockBean(CsrfTokenRepository,'repo')
createAppContext()
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
CsrfToken token = new CsrfToken("X-CSRF-TOKEN","_csrf", "abc")
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.method = "POST"
@@ -40,7 +40,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -96,7 +95,9 @@ public class SessionManagementConfigurerServlet31Tests {
request.setMethod("POST");
request.setParameter("username", "user");
request.setParameter("password", "password");
CsrfToken token = new HttpSessionCsrfTokenRepository().generateAndSaveToken(request, response);
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
CsrfToken token = repository.generateToken(request);
repository.saveToken(token, request, response);
request.setParameter(token.getParameterName(),token.getToken());
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);