diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java index 89d4ec5845..30998a4c30 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java @@ -31,6 +31,7 @@ import org.springframework.util.StringUtils; * Properties for the security aspects of an application. * * @author Dave Syer + * @author Andy Wilkinson */ @ConfigurationProperties(prefix = "security") public class SecurityProperties implements SecurityPrerequisite { @@ -162,22 +163,22 @@ public class SecurityProperties implements SecurityPrerequisite { /** * Enable cross site scripting (XSS) protection. */ - private boolean xss; + private boolean xss = true; /** * Enable cache control HTTP headers. */ - private boolean cache; + private boolean cache = true; /** * Enable "X-Frame-Options" header. */ - private boolean frame; + private boolean frame = true; /** * Enable "X-Content-Type-Options" header. */ - private boolean contentType; + private boolean contentType = true; /** * HTTP Strict Transport Security (HSTS) mode (none, domain, all). diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java index f9d2d2d57d..2d6fa77e1c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java @@ -75,6 +75,7 @@ import org.springframework.util.StringUtils; * * * @author Dave Syer + * @author Andy Wilkinson */ @Configuration @EnableConfigurationProperties @@ -101,17 +102,17 @@ public class SpringBootWebSecurityConfiguration { writer.setRequestMatcher(AnyRequestMatcher.INSTANCE); configurer.addHeaderWriter(writer); } - if (headers.isContentType()) { - configurer.contentTypeOptions(); + if (!headers.isContentType()) { + configurer.contentTypeOptions().disable(); } - if (headers.isXss()) { - configurer.xssProtection(); + if (!headers.isXss()) { + configurer.xssProtection().disable(); } - if (headers.isCache()) { - configurer.cacheControl(); + if (!headers.isCache()) { + configurer.cacheControl().disable(); } - if (headers.isFrame()) { - configurer.frameOptions(); + if (!headers.isFrame()) { + configurer.frameOptions().disable(); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java index bd575f19b3..cb7f8c2861 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java @@ -51,6 +51,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.FilterChainProxy; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @@ -60,6 +61,8 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.assertEquals; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -68,6 +71,7 @@ import static org.junit.Assert.assertTrue; * * @author Dave Syer * @author Rob Winch + * @author Andy Wilkinson */ public class SpringBootWebSecurityConfigurationTests { @@ -189,6 +193,49 @@ public class SpringBootWebSecurityConfigurationTests { assertEquals(HttpStatus.NOT_FOUND, result.getStatusCode()); } + @Test + public void defaultHeaderConfiguration() throws Exception { + this.context = SpringApplication.run(VanillaWebConfiguration.class, + "--server.port=0"); + MockMvc mockMvc = MockMvcBuilders + .webAppContextSetup((WebApplicationContext) this.context) + .addFilters((FilterChainProxy) this.context + .getBean("springSecurityFilterChain", Filter.class)) + .build(); + mockMvc.perform(MockMvcRequestBuilders.get("/")) + .andExpect(MockMvcResultMatchers.header().string("X-Content-Type-Options", + is(notNullValue()))) + .andExpect(MockMvcResultMatchers.header().string("X-XSS-Protection", + is(notNullValue()))) + .andExpect(MockMvcResultMatchers.header().string("Cache-Control", + is(notNullValue()))) + .andExpect(MockMvcResultMatchers.header().string("X-Frame-Options", + is(notNullValue()))); + } + + @Test + public void securityHeadersCanBeDisabled() throws Exception { + this.context = SpringApplication.run(VanillaWebConfiguration.class, + "--server.port=0", "--security.headers.content-type=false", + "--security.headers.xss=false", "--security.headers.cache=false", + "--security.headers.frame=false"); + + MockMvc mockMvc = MockMvcBuilders + .webAppContextSetup((WebApplicationContext) this.context) + .addFilters( + this.context.getBean("springSecurityFilterChain", Filter.class)) + .build(); + mockMvc.perform(MockMvcRequestBuilders.get("/")) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()) + .andExpect(MockMvcResultMatchers.header() + .doesNotExist("X-Content-Type-Options")) + .andExpect( + MockMvcResultMatchers.header().doesNotExist("X-XSS-Protection")) + .andExpect(MockMvcResultMatchers.header().doesNotExist("Cache-Control")) + .andExpect( + MockMvcResultMatchers.header().doesNotExist("X-Frame-Options")); + } + @Configuration @Import(TestWebConfiguration.class) @Order(Ordered.LOWEST_PRECEDENCE) diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index fcd6e79f90..a890d53700 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -303,10 +303,10 @@ content into your application; rather pick only the properties that you need. security.basic.path= # /** security.basic.authorize-mode= # ROLE, AUTHENTICATED, NONE security.filter-order=0 - security.headers.xss=false - security.headers.cache=false - security.headers.frame=false - security.headers.content-type=false + security.headers.xss=true + security.headers.cache=true + security.headers.frame=true + security.headers.content-type=true security.headers.hsts=all # none / domain / all security.sessions=stateless # always / never / if_required / stateless security.ignored= # Comma-separated list of paths to exclude from the default secured paths