Hi all,
I’ve spent some time trying to figure out how to attack the issue of CSP + Proxy with SSL termination, this mail contains my findings (warning, long and technical).
First of all, what’s going on?
GeoServer code, Spring security, and Wicket internals, all tend to use HTTPServletReponse.redirect(“${relativePath}”), where relativePath is often “web”.
From Servlet API javadoc (thanks Steve) we learn the method should be implemented by the container by turning the relative path into an absolute URL.
That is done by taking the HTTP Host header, which is part of the spec and guaranteed to be there, the context path (e.g., “geoserver”) and the relative path provided as an argument.
The protocol is an issue: there is not true standard HTTP header indicating the protocol (there are non-standard headers though, more on this later), so the servlet container will use whatever protocol it received the request onto.
Now, it’s pretty common practice that SSL is handled by proxy in front of GeoServer, with nginx and apache being common choices. So the request goes to, say “https://gs-main.geosolutionsgroup.com/geoserver/web/”, the proxy handles SSL and forwards the request as “http://:8080/geoserver/web/” and when doing a redirect the servlet container returns a HTTP 302 with a Location header stating “http://gs-main.geosolutionsgroup.com/geoserver/myChosenPath”. Whoops!
So far everything worked anyways, because most sites have transitioned in recent years from HTTP to HTTPS and have a built-in configuration redirecting any HTTP request to HTTPS.
So it works by doing this:
- GeoServer sends a redirect with Location header set to http://gs-main.geosolutionsgroup.com/geoserver/myChosenPath
- The browser receives exactly that, and opens that new URL
- The proxy in turns performs another redirect, this time to https://gs-main.geosolutionsgroup.com/geoserver/myChosenPath
- The browser follows the new path and we’re back in business
This happens on a set of very common actions in the GeoServer UI: login, logout, switch tab in the tabbed layer pages, click save in a number of pages where save is implemented as an Ajax button.
Introduce CSP, and the browser gets instructed not to reach out to pages outside of the origin server and protocol, and our little set of actions above stops at point 2., with errors only visible if you open the developer tools.
How to get out of it? I found and considered a few approaches.