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

Reply via email to