Home > Back-end >  Content Security Policy and REST API call - how does it work?
Content Security Policy and REST API call - how does it work?

Time:11-25

I am finding it difficult to understand an error thrown by my app when trying to invoke a REST API.

My app, a pure HTML, JavaScript based using jQuery, is running in Jetty server. The server has implemented Content-Security-Policy:

Custom HTTP headers to be added to our responses: Content-Security-Policy: 
default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; 
img-src 'self' data:; style-src 'self' 'unsafe-inline'; base-uri 'self'; 
frame-ancestors 'self'; font-src 'self';frame-src 'self'|X-Frame-Options: 
SAMEORIGIN|X-Content-Type-Options: nosniff|X-XSS-Protection: 1; mode=block|
Referrer-Policy: strict-origin|Feature-Policy: 'none'|Strict-Transport-Security: 
max-age=63072000; includeSubDomains; preload

I understand this part. Anyone trying to access my app has to adhere to these restrictions.

However, the JavaScript code in my app tries to call a Spring Boot REST API running on same Linux VM (http://localhost:8080/... or http://server-host-name:8080/...). When doing so, I get Content Security Policy violated when accessing http://localhost:8080...: content-src 'self'.This confuses me. Trying to access my app in Jetty without adhering to the security policy should raise error. But why would it throw an error when app in Jetty it is calling a Spring Boot API which doesn't have any such restriction?

Do I need to relax the Content Security Policy restriction on Jetty server? If so, why?

Summary:
REST API: Spring Boot HTTP API running on same Linux VM
Jetty Server: CSP restriction as mentioned above
JavaScript app in Jetty: Calling Spring Boot API

CodePudding user response:

Briefly: you have to add http://localhost:8080 to the default-src directive.

Tl; DR;: the 'self' token is insidious, because you intuitively endow him with powers that he fails to fulfill.

Browsers substisute the 'self' token with the "tuple origin" (scheme host_name port_number) of the page URL from the browser's address bar, and then they add some CSP-specific magic:

  • allow ws: host_name ws_standard_port
  • allow upgrade ws: to wss: and http: to https: in CSP3-browsers

So, what do we have:

  1. Your app uses fetch to access Spring Boot REST API which should be covered by missing connect-src directive, therefore browser uses default-src as fallback.
  2. Browser transform default-src 'self' to the default-src http://your_domain.com:80 or default-src https://your_domain.com:443 (depending on how you load the page).

As you can see both of these do not allow http://localhost:8080. Although actually localhost is an alias of the your_domain.com, but CSP does not know this, and just blocking because of mismatch host_name port_number.

But if you will load app with the http://localhost:8080/your_app_path url, fetch to REST API will be allowed because covered by 'self'

  • Related