Search code examples
javaspringspring-securitywebsecuritycross-origin-resource-policy

Exclude specific resource page(s) from Cross-Origin-Resource-Policy same-origin header in Spring WebSecurityConfigurerAdapter


We have a Java class that extends Spring's WebSecurityConfigurerAdapter and sets all of our security headers and such. Leaving only the relevant parts of the code, it's currently like this:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   ...

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      ...

      http.headers()
          ...
          .and()
          .crossOriginResourcePolicy()
              .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN)
          .and()
          ...;
}

(using spring-framework.version 5.3.39; org.springframework.boot/spring-boot-starter-parent 2.7.18; and JDK version 21)

If someone now tries to access for example an image from our website through their own website, e.g.

  1. Create a local test.html file.
  2. Change and save its contents to <html><body> <img src="https://myexamplewebsite.com/animals/uploaded_documents/dog.jpg"> </body></html>.
  3. Open this HTML file in your browser.

They'll see a broken image and get the following console error (tested in Google Chrome):

GET https://myexamplewebsite.com/animals/uploaded_documents/dog.jpg net::ERR_BLOCKED_BY_RESPONSE.NotSameOrigin 200 (OK)

Which is as expected.

However, I'd like to make an exception to the above header for resource images from a specific path (e.g. /public_resources/**).
So, it would still give the above for that general image URL, but won't give the error for let's say the image URL https://myexamplewebsite.com/public_resources/logo.jpg.
Of course, I'd still like to retain all other headers for this public_resources URL, as well as the Cross-Origin-Resource-Policy same-origin header for all images (and other resources) not in this /public_resources/** path.

PS: Our host website, for which I've used https://myexamplewebsite.com in my question here, is generic based on the customer and optional branch within that company (e.g. https://branchname.companyname.nl/ or https://companyname.nl/), so I cannot hard-code it in my defined headers.


As for its use-case, why I want to accomplish this: we do want this header in general, but images from this /public_resources/ path are sometimes used in email templates (e.g. logos), and when a customer opens this email, they'll currently see a broken image link due to this header. Hence why any image from this /public_resources/ domain should lack this header, so those images can be viewed when embedded within other documents.


I've tried overwriting Spring's standard crossOriginResourcePolicy() implementation, by adding the following after everything else in the configure method:

http.antMatches("/public_resources/**")
    .headers()
    .addHeaderWriter(new StaticHeadersWriter("Cross-Origin-Resource-Policy", "none"))

But that overrides not just that header, but almost everything for some reason, and also on other pages.

I've also tried something similar as in this answer, creating a separated class which extends WebSecurityConfigurerAdapter, and doing the above snipped of code within its overwritten configure method, but that didn't work either.


Solution

  • Although .antMatcher(String) lacks any invert capability for its 'regex', there is also an actual regex matcher method available: .regexMatcher(String).

    So I've removed this from my original code:

    .and()
    .crossOriginResourcePolicy()
      .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN)
    

    And added this later on:

    // Set the following header(s) on each request as well, with the sole exception
    // of requests that access the resources within the /public_resources/** folder:
    http.regexMatcher("^(?!/public_resources/).*$")
        .headers()
        .crossOriginResourcePolicy()
          .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN);
    

    And now my images from this public_resources domain-path won't have the Cross-Origin-Resource-Policy header, and can therefore be viewed, but every other image/resource will have this header and cannot be viewed from within external sources.