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 <https://javaee.github.io/javaee-spec/javadocs/javax/servlet/http/HttpServletResponse.html#sendRedirect-java.lang.String-> (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*://<internal-gs-host>: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: 1. GeoServer sends a redirect with Location header set to *http*:// gs-main.geosolutionsgroup.com/geoserver/myChosenPath 2. The browser receives exactly that, and opens that new URL 3. The proxy in turns performs another redirect, this time to *https*:// gs-main.geosolutionsgroup.com/geoserver/myChosenPath 4. 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. ------------------------------------------------------------------------------------- *First one: have GeoServer redirect to a full URL every time*. That's allowed by the servlet API and we could build the full redirect URL by using the proxy base URL configuration. Redirects are done also in code outside of GeoServer, but this could be performed in a servlet wrapper. However, I know for a fact it's going to break secure deploys that don't expose the GUI on the web... the typical situation there is that they access GeoServer directly within the DMZ, on the actual GeoServer IP, and the GUI needs to keep on working in that case. We'd need some way to tell apart the local direct access from the "through proxy" access. Which would mean, fiddling with the proxy configuration anyways. Meh! *Second one: tell the web container which protocol to use*. The non standard, yet common, "X-Forwarded-Proto" header can be set to "https" as a way to tell the container which protocol it should use for redirects. However, containers will, out of the box, ignore it, because the header is not guarnteed to be there and it may be manipulated by clients to mount some sort of attack. Futhermore, each container has a different way to configure using the header. For example, in Tomcat it would be declaring a Valve in server.xml: <Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" remoteIpHeader="X-Forwarded-For" internalProxies=".*" /> But in Jetty, it would be something completely different in start.ini: --module=forwarded (mind, untested) and so on for each different servlet container. *Third one: tell the proxy to switch the protocol* The proxy can be configured to switch the proxy in redirect calls. Again, we're facing a case by case scenario. For nginx (the case that I've actually tried, and can confirm it works): proxy_redirect http://$host/ https://$host/; For apache (mind, untested): Header edit Location ^http://(.*)$ https://$1 and so on, a different way to do this in each proxy software. ------------------------------------------------------------------------------------- Which one to choose? I've made a few questions around and asked people about this, as well as a few AIs, the summary is: - SSL termination is normally in the hands of system admins, which may or may not dealing with the GeoServer setup - Those same people are familiar with their proxy of choice, but very often, only lightly familiar with Tomcat configuration. Asking around about the Valve, I could not find anyone that knew what it was, while the nginx setting was known, although not normally used - Asking AIs confirmed that web container setup is well known only in Java heavy shops, but a number of GeoServer deploys are in environments where GS is the only Java app around. So I'd suggest to go an document how to configure proxies. I can offer an example of Nginx. Can anyone else test the Apache approach? And then we can ask users to contribute approaches for other proxies, once the admins know what to do, they should be able to figure out the specific setting quickly. Regards, Andrea Aime == GeoServer Professional Services from the experts! Visit http://bit.ly/gs-services-us for more information. == Ing. Andrea Aime @geowolf Technical Lead GeoSolutions Group phone: +39 0584 962313 fax: +39 0584 1660272 mob: +39 339 8844549 https://www.geosolutionsgroup.com/ http://twitter.com/geosolutions_it ------------------------------------------------------- Con riferimento alla normativa sul trattamento dei dati personali (Reg. UE 2016/679 - Regolamento generale sulla protezione dei dati “GDPR”), si precisa che ogni circostanza inerente alla presente email (il suo contenuto, gli eventuali allegati, etc.) è un dato la cui conoscenza è riservata al/i solo/i destinatario/i indicati dallo scrivente. Se il messaggio Le è giunto per errore, è tenuta/o a cancellarlo, ogni altra operazione è illecita. Le sarei comunque grato se potesse darmene notizia. This email is intended only for the person or entity to which it is addressed and may contain information that is privileged, confidential or otherwise protected from disclosure. We remind that - as provided by European Regulation 2016/679 “GDPR” - copying, dissemination or use of this e-mail or the information herein by anyone other than the intended recipient is prohibited. If you have received this email by mistake, please notify us immediately by telephone or e-mail
_______________________________________________ Geoserver-devel mailing list Geoserver-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/geoserver-devel