禁用 Spring Security 标头不起作用

Posted

技术标签:

【中文标题】禁用 Spring Security 标头不起作用【英文标题】:Disabling Spring Security headers does not work 【发布时间】:2016-06-30 13:59:16 【问题描述】:

我需要在我的 Spring Security conf 中禁用缓存控制标头。

根据文档,一个简单的http.headers.disable() 应该可以做到,但我仍然看到

Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Expires:0
Pragma:no-cache

响应中的标题。

我当前的安全配置是:

http.antMatcher("/myPath/**") // "myPath" is of course not the real path
    .headers().disable()
    .authorizeRequests()
     // ... abbreviated
    .anyRequest().authenticated();

到目前为止我尝试过的事情:

application.properties

我添加了security.headers.cache=false 行,但这并没有什么不同。

使用过滤器

我尝试了以下过滤器:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
  chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) 
      @Override
      public void setHeader(String name, String value) 
        if (name.equalsIgnoreCase("Cache-Control")) 
          value = "";
         else if (name.equalsIgnoreCase("Expires")) 
          value = "";
         else if (name.equalsIgnoreCase("Pragma")) 
          value = "";
        
        super.setHeader(name, value);
      
  );

添加日志后,我看到此过滤器仅写入 X-XSS-Protection 标头,所有缓存标头都稍后写入某处,此过滤器无权“覆盖”它们。即使我将此过滤器添加到安全过滤器链的最后位置也会发生这种情况。

使用拦截器

我尝试了以下拦截器:

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception 
    String requestUri = request.getRequestURI();
    response.setHeader("Cache-Control", "max-age=3600");
    response.setHeader("Expires", "3600");
    response.setHeader("Pragma", "");

这(完全可以预见)只是添加了标头,这意味着除了拦截器添加的标头之外,原始的 no-cache 标头仍然出现。

我的智慧到此为止。如何摆脱 Spring security 设置的缓存控制头?

【问题讨论】:

对我来说,感谢您的问题,在我的 application.properties 添加:security.headers.cache=false 后,它起作用了 【参考方案1】:

你说得对

http
    .headers().disable()
    ...

将禁用您的标题。如果您只想禁用缓存控制,可以使用以下方法:

http
    .headers()
        .cacheControl().disable()
        .and()
    ...

我已经发布了 a sample,它展示了与 with a test 一起工作的情况。

我的猜测是您遇到的问题是您有多个 HttpSecurity 配置。请记住,如果您有:

http
    .antMatchers("/myPath/**")
    ...

只有以 /myPath/ 开头的 URL 会受到影响。此外,如果您有多个 HttpSecurity 实例,则按顺序考虑每个 HttpSecurity 实例,并且仅使用第一个 HttpSecurity 实例。例如,如果您有:

@Configuration
@Order(1)
public class MyPathAdminWebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
            .antMatchers("/myPath/admin/**")
            .authorizeRequests()
                .anyRequest().hasRole("ADMIN");
    


@Configuration
@Order(2)
public class MyPathWebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
            .antMatchers("/myPath/**")
            .headers()
                .cacheControl().disable();
    


@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
            .authorizeRequests()
                .anyRequest().authenticated();
    

如果您请求 /myPath/admin/abc

首先考虑MyPathAdminWebSecurityConfig。由于/myPath/admin//myPath/admin/ 开头,我们将使用MyPathAdminWebSecurityConfig 并且不考虑任何其他配置。这意味着您将期望获得此请求的标头。

【讨论】:

你的假设是错误的。对于现有配置的子路径,我没有多个安全配置。我确实有其他路径的其他安全配置(无论如何都与“/mypath”无关),但这些不应该是一个真正的问题,我不需要在那里禁用标题。【参考方案2】:

您需要一个扩展 WebSecurityConfigurerAdapter 的类,并使用两个覆盖的配置方法来配置过滤器和身份验证提供程序。例如,以下内容至少可以工作:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfigDemo extends WebSecurityConfigurerAdapter 

    @Autowired
    private DemoAuthenticationProvider demoAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception         

    // Prevent the HTTP response header of "Pragma: no-cache".
    http.headers().cacheControl().disable();

    

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception         
        auth.authenticationProvider(demoAuthenticationProvider);        
        


您还可以对公共静态资源完全禁用 Spring Security,如下所示(在与上述相同的类中):

@Override
public void configure(WebSecurity web) throws Exception 
    web.ignoring().antMatchers("/static/public/**");

这需要配置两个资源处理程序来正确获取缓存控制标头:

@Configuration
public class MvcConfigurer extends WebMvcConfigurerAdapter
        implements EmbeddedServletContainerCustomizer 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) 
        // Resources without Spring Security. No cache control response headers.
        registry.addResourceHandler("/static/public/**")
            .addResourceLocations("classpath:/static/public/");

        // Resources controlled by Spring Security, which
        // adds "Cache-Control: must-revalidate".
        registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/")
            .setCachePeriod(3600*24);
    

【讨论】:

【参考方案3】:

可能会有帮助:

@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter 

@Override
protected void configure(HttpSecurity http) throws Exception 
    http
    // ...
    .headers()
        .defaultsDisabled()
        .cacheControl();


http://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html#headers-cache-control

【讨论】:

感谢我一直在寻找的defaultsDisabled()【参考方案4】:

所以,我自己找到了答案: 最后,我通过在我的 yml 配置文件中创建一个名为 spring.resources.cachePeriod 的新条目并将其设置为不同于 0 的值,从而使 Cache-Control 标头更改其值。不好的是所有资源都使用这个设置,所以据我所知,没有办法根据资源使其不同。

this question 的回答很有帮助。

【讨论】:

【参考方案5】:

所以我遇到了类似的问题,希望我的大多数 REST 端点具有 Spring 正在注入的标准“不要缓存我”标头,但我想在一个端点上插入我自己的。

在您提供给 ResponseEntry 的 HttpHeaders 对象中指定您自己的无效。

工作原理是直接在 HttpServletResponse 上显式设置标头。

Spring 正在设置“Cache-Control”、“Pragma”和“Expires”。下面演示了如何覆盖和设置一个 1 分钟的缓存:

response.setHeader("Cache-Control", "max-age=60");
response.setHeader("Pragma", "");
HttpHeaders headers = new HttpHeaders();
headers.setExpires(System.currentTimeMillis()+60000);
return new ResponseEntity<>(body, headers, HttpStatus.OK);

【讨论】:

【参考方案6】:

在我的应用程序类上通过@EnableOAuth2Sso 启用 OpenId Connect 后,我​​遇到了这个问题。经过大约六个小时的调试和阅读文档后,发现必须将 @EnableOAuth2Sso 放在 WebSecurityConfigurerAdapter 上,否则默认设置将覆盖自定义设置:

// In Application.java
@SpringBootApplication
public class Application 
    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    


//In WebSecurity.java
@Configuration
@EnableOAuth2Sso  // <- This MUST be here, not above
public class WebSecurity extends WebSecurityConfigurerAdapter 
    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.headers().disable();
    

不好

// In Application.java
@SpringBootApplication
@EnableOAuth2Sso  // <- Will overwrite config below
public class Application 
    //...


@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter 
    //...

【讨论】:

以上是关于禁用 Spring Security 标头不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security JWT - 通过授权标头的邮递员身份验证有效,但从我的 Angular 前端不起作用

预告片标头中的 Content-Security-Policy 标头不起作用

调用 j_spring_security_logout 不起作用

Spring-security-cas 插件单点注销不起作用

spring.security 禁止 curl 发布请求

Spring Security 角色不起作用