How to Turn Your Spring Boot App into a Fort Knox

Lock Down Your Spring Boot App Like Fort Knox

How to Turn Your Spring Boot App into a Fort Knox

Securing your Spring Boot web application is like locking your front door and turning on the alarm system when you leave the house. It’s absolutely essential to implement security best practices to protect your users’ data and fend off common web vulnerabilities like unwanted online intruders. Three major areas to keep your eyes on are CORS (Cross-Origin Resource Sharing), CSRF (Cross-Site Request Forgery) protection, and HTTPS (Hypertext Transfer Protocol Secure). Let’s take a look at each of these essentials and how to nail their implementation in your Spring Boot application without breaking a sweat.


Making Sense of CORS

So, what’s all this fuss about CORS? Imagine you’re working on a web application and it needs to fetch resources from different domains. But, there’s a catch—by default, web browsers follow the same-origin policy. This nifty policy stops a web page from making requests to a different domain, protocol, or port than the one it came from. Pretty strict, right? Good news: CORS allows those requests across domains, making your modern web application dreams come true.

To get CORS cooking in Spring Boot, you’ll need to set it up to allow cross-origin requests either globally or just for specific controllers.

Global CORS Configuration

Want to open your app to cross-origin requests globally? Just configure it in your security settings. Check out this example:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:8080");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

In plain English, this code says: “Hey, allow requests from http://localhost:8080 with any kind of header and method for all endpoints (’/**’)“.

Per-Controller CORS Configuration

What if you only want to enable CORS for specific controllers? No problem! With the @CrossOrigin annotation, you can specify this right at the controller level.

@CrossOrigin(maxAge = 3600, allowCredentials = "true")
@RestController
@RequestMapping("cors-library/managed/books")
public class LibraryController {

    @GetMapping
    public ResponseEntity<List<BookDto>> getBooks(@RequestParam String type) {
        // Your logic here
    }
}

This setup allows you to drill down and specify which origins, headers, and methods are allowed for particular controllers or methods.


Taming the CSRF Beast

Cross-Site Request Forgery (CSRF) attacks sound scary, right? They trick users into performing unintended actions on a web application they’re logged into. Think unwanted money transfers or embarrassing social media posts. Good thing Spring Security comes with built-in CSRF protection.

Enabling CSRF Protection

Spring Security’s got your back, especially for sensitive HTTP methods like POST, PUT, and DELETE.

Here’s the deal:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
        return http.build();
    }
}

Essentially, this code snippet configures Spring Security to store the CSRF token in a cookie, with the httpOnly flag set to false so JavaScript can access it.

Handling CSRF Tokens in SPAs

If you’re working with Single-Page Applications (SPAs), handling CSRF tokens is a bit different. Here’s how you can get it done:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf((csrf) -> csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()));
        return http.build();
    }

    private static class SpaCsrfTokenRequestHandler extends CsrfTokenRequestAttributeHandler {
        private final CsrfTokenRequestHandler delegate = new XorCsrfTokenRequestAttributeHandler();

        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
            delegate.handle(request, response, csrfToken);
        }
    }
}

This configuration ensures the CSRF token is handled correctly, providing protection against BREACH attacks even for SPAs.


The HTTPS Must-Have

HTTPS is a no-brainer for securing the connection between your client and server. Imagine someone eavesdropping on your users’ data—yikes!

Generating SSL Certificates

First, you’ll need some SSL certificates. OpenSSL to the rescue! Generate a self-signed certificate like this:

openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365

Configuring Spring Boot for HTTPS

Got your certificates? Time to configure Spring Boot:

server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-alias=tomcat
server.ssl.enabled=true

If your certificates aren’t in a PKCS12 keystore format already, convert ‘em:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12

Disabling HTTP and Enabling HTTPS

To ensure all your traffic stays secure, disable HTTP and route everything through HTTPS.

@Configuration
public class WebServerConfig {

    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerCustomizer() {
        return (factory -> factory.setPort(8443));
    }

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createHttpConnector());
        return tomcat;
    }

    private Connector createHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

Voilà! Now all your HTTP requests are automatically redirected to HTTPS, keeping everything safe and sound.


Putting It All Together

Combining all these security measures is where the magic happens. You get a robust and secure Spring Boot application that stands tough against web vulnerabilities.

Here’s how you can tie everything together:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:8080");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

@Configuration
public class WebServerConfig {

    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerCustomizer() {
        return (factory -> factory.setPort(8443));
    }

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createHttpConnector());
        return tomcat;
    }

    private Connector createHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

Wrapping Up

Securing your Spring Boot application shouldn’t give you nightmares. By enabling CORS, implementing CSRF protection, and using HTTPS, you can sleep easy knowing your application is safe from common threats. Just take things step by step, configure these settings carefully, and enjoy the peace of mind that comes with a robustly secured application.

And remember, your users might not see what’s under the hood, but they’ll definitely appreciate the protection you’ve put in place to keep their data safe.