How does .headers().frameOptions().disable() work?
Asked Answered
W

2

8

About Spring Security to let, control and get access to the h2 web console

I read these two posts:

In conclusion is mandatory use the following ("improved" in someway):

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .mvcMatchers("/admin/**").hasRole("ADMIN")
            ...
            .mvcMatchers("/h2-console/**").hasRole("ADMIN")
            .and()
        .csrf().ignoringAntMatchers("/h2-console/**")
            .and()
        .headers().frameOptions().disable()
            .and()

From above is better use .csrf().ignoringAntMatchers("/h2-console/**") instead of csrf().disable() it for security reasons because the disable point applies only to /h2-console/, the latter is global and is not recommended.

Until here I am fine. And I am able to see the H2 web console once the login process happened and the user has the required role.

enter image description here

Now is mandatory use .headers().frameOptions().disable(), if is not used happens the following:

enter image description here

The localhost refused to connect message appears to any inner block when the mouse's cursor is over any of them

My doubts are:

  1. How does .headers().frameOptions().disable() work?
  2. Is safe to use that sentence for Production Environment? Consider the difference between .csrf().ignoringAntMatchers("/h2-console/**") and csrf().disable(), where the former is specific and the latter is "global" (and is not recommended). Therefore perhaps would be available a specific configuration much better than .headers().frameOptions().disable() (at a first glance for me is a "global" configuration) to only apply to /h2-console/
  3. Could .headers().frameOptions().disable() have any negative effect, directly or indirectly, for other configure(HttpSecurity http) configuration? (Mostly for Production)
Warrenne answered 26/1, 2021 at 0:21 Comment(0)
J
22

First, let's look at the X-Frame-Options response header.
This header can be used to indicate whether or not a browser should be allowed to render a page in a <frame> or <iframe>.
Sites can use this to avoid Clickjacking attacks, by ensuring that their content is not embedded into other sites.

Spring Security sets the X-Frame-Options response header to DENY by default.
This tells the browser that the page cannot be displayed in a frame, regardless of the site attempting to do so.
Since the H2 console UI is using <frame> elements, these will not be rendered and you will see the error screen that you shared in your question.

Spring Security allows you to customise this behaviour using .headers().frameOptions() in the Security DSL.
If you choose to disable the X-Frame-Options header (not recommended) by setting .headers().frameOptions().disable(), then Spring Security will not add the X-Frame-Options header to the response.
This means your application could be rendered in a frame, and also could be vulnerable to Clickjacking attacks.

Instead of disabling it, it is sufficient to set X-Frame-Options to SAMEORIGIN, for this use case.

http
    .headers(headers -> headers
        .frameOptions(frameOptions -> frameOptions
            .sameOrigin()
        )
    )

This tells the browser that the page can only be displayed in a frame on the same origin as the page itself.

Since the frames in the H2 console UI (such as http://localhost:8080/h2-console/tables.do) are on the same origin as the the H2 console (http://localhost:8080/h2-console), the browser will allow them to be displayed.

However, if a different (potentially malicious) website tried to embed one the pages, the browser would not allow it.

Jecho answered 29/1, 2021 at 14:29 Comment(1)
Excellent explanation, just in case consider to share your snippet code in a non-lambda version too. Therefore both versions are availableWarrenne
L
1
@Configuration
@EnableWebSecurity

public class WebSecurityConfig {
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
    // ...
      .headers(headers -> headers
        .frameOptions(frameOptions -> frameOptions
          .disable()
        )
      );
      return http.build();
  }
}
Lastminute answered 18/5 at 22:4 Comment(1)
Thank you for posting this answer. While this code may answer the question, might you please edit your post to add an explanation as to why/how it works? This can help future readers learn and apply your answer. You are also more likely to get positive feedback (upvotes) when you include an explanation.Castalia

© 2022 - 2024 — McMap. All rights reserved.