Ssl accelerators java app servers and redirects
9:49 PM
Courtesy of James Waldrop
It's very common for web applications to send redirects after a form POST submission, as it works around the dreaded page-refresh = double form submission problem that can cause nightmare scenarios like double credit card charges and the like. A redirect is a response by the web server asking the web browser to load another page. Unlike URL's embedded in HTML, redirects cannot be "relative", meaning they must be fully qualified with scheme, host, and port parts if required.
As I'm sure most everyone is aware, hardware SSL accelerators offload the cpu-intensive SSL operations and allow a web application to deal strictly with HTTP. Effectively the accelerator is encapsulating and de-encapsulating the SSL "headers" for the web application. As a result, the web application is unaware of operating in an HTTPS context, and in fact has no way to identify that customer browsers are operating in such a context except through external configuration of some sort. It's not possible to automatically identify that a hardware accelerator is in place if you're writing code that lives in the web application space.
Finally, despite the fact that redirects cannot be relative, it's very common to try and support specifying them relatively in software. This is done by having web frameworks automatically handle the generation of the final redirection URL, using knowledge the web application has about the context it's running in. Normally this allows for things like transparently moving the web application from host to host (dev to test, or test to staging, etc) without having to re-specify every redirect in some configuration file or build a facility in the web application to allow 'smart' redirect writing. Since a web application can have potentially many redirects, this is a Good Thing(tm).
Those of you who read murder mysteries have probably already connected the dots here, but just to go all Agatha Christie on you I'll lay it out myself. The fact that a web application behind a hardware SSL accelerator cannot identify that it's running in an HTTPS/SSL context means that when redirects are automatically generated by a framework, the URLs are generated incorrectly. The scheme portion is generated as http, resulting in a page such as:
https://www.firepondondemand.com/app/blah.do?somestuff=whatever
redirecting to:
http://www.firepondondemand.com/foo/bar.do?baz=bat
There are two potential problems here. Either http traffic is not accepted by the web application, in which case the second URL fails to load, or http traffic is accepted but the person has moved from a secure context to an insecure context. Not only is this a potential problem for application security, Internet Explorer will pop up a nasty dialog saying that you've just been redirected to an insecure context and your life secrets may be leaking into the ether. Neither scenario is very good for customers.
Now that I have half my audience going "yeah yeah, get to the good stuff", I'll tell you how to fix this.
There's a solution which may work but which adds load to the network engineering team and to the accelerator itself. Because this problem is relatively common, the BigIP supports a profile setting known as Redirect Rewriting. If Redirect Rewrites are enabled on a profile used by your customer, their redirects might get automatically rewritten so as to change the http to https. This didn't work for Firepond, and since there is a solution at the webapp side, we didn't pursue why that is the case, but you should be aware of it as a potential solution for applications which have no way to fix this problem on their end. To be 100% clear, Redirect Rewrites are not normally turned on, and they may have an adverse effect on the application if redirects are generated which should not be rewritten automatically. Use With Caution.
The nicer solution, the one I'm writing this email about, is to somehow affect the framework's redirect URL generation facility so that it writes them correctly in the first place, without a ton of configuration. It turns out that this is possible in Tomcat, and since Tomcat is the embedded servlet engine for JBoss, Weblogic, and more, it becomes a transitive solution for most (all?) of our customers running in a Java environment.
As you might be aware, web applications sometimes run behind a proxy. The SSL accelerators we use aren't proxies, so it doesn't exactly spring to mind to treat them like proxies, but if we do our eyes naturally move to a portion of the Tomcat configuration regarding proxies. Specifically, you can specify the proxy's name, port, and most importantly the scheme the proxy uses to talk to clients. We can use this ability to configure Tomcat to behave as if we're running in an SSL context without actually incurring the CPU/configuration cost of running SSL directly on the web servers. Doing this is a very simple change:
1) Find the server.xml config file for your app server. It should mention Tomcat/Catalina stuff, if it doesn't you're in the wrong file.
2) Find the section of the file with a <Connector ...> tag referring to the port your app server runs on. In JBoss this is done with a variable, and in Tomcat the port is specified directly (usually as 8080). I haven't done this for Weblogic, but I imagine it's similar to JBoss. This tag should not be commented out, and many are. XML comments are the same as HTML, and read <!-- stuff commented out -->. So if that's wrapped around the tag you're looking at, you've got the wrong tag.
3) Once you've found it, add three attributes to this tag:
proxyName="www.yourcustomer.com"
proxyPort="443"
scheme="https"
4) Restart your app server and test that the change works. I reccomend using Firefox and the LiveHTTPHeaders plugin to see what's going on directly.
It'd be nice if you didn't have to set the proxyName, since this is a configuration setting you'll have to change depending on whether the application is running on a staging URL or not, but unfortunately Tomcat will not honor the scheme setting if you don't. You may also find some reference to setting secure="true" in Googling around about this problem. Don't do it. That tells Tomcat to really turn SSL on, at which point it starts to look for certs and keystores and just generally goes down the path we're trying to avoid with the SSL accelerator in the first place.
And that's it! If you have any questions/problems doing this sort of thing For Real, feel free to contact me via the usual routes and I'll be happy to help.
p.s. Some of you may notice a resemblance between this problem and a problem that some SOAP frameworks have automatically generating WSDL's. This is the same problem, and can be solved the same way. So, if your customer complains that their app is suddenly generating WSDL's with http endpoints when they should be https, you can probably fix it as I've described above. This is an issue with every Java-based SOAP framework I've used, and can also be worked around by hard-coding the WSDL. There are other reasons to hard-code your WSDL, so this might be acceptable, but often it's sub-optimal.
It's very common for web applications to send redirects after a form POST submission, as it works around the dreaded page-refresh = double form submission problem that can cause nightmare scenarios like double credit card charges and the like. A redirect is a response by the web server asking the web browser to load another page. Unlike URL's embedded in HTML, redirects cannot be "relative", meaning they must be fully qualified with scheme, host, and port parts if required.
As I'm sure most everyone is aware, hardware SSL accelerators offload the cpu-intensive SSL operations and allow a web application to deal strictly with HTTP. Effectively the accelerator is encapsulating and de-encapsulating the SSL "headers" for the web application. As a result, the web application is unaware of operating in an HTTPS context, and in fact has no way to identify that customer browsers are operating in such a context except through external configuration of some sort. It's not possible to automatically identify that a hardware accelerator is in place if you're writing code that lives in the web application space.
Finally, despite the fact that redirects cannot be relative, it's very common to try and support specifying them relatively in software. This is done by having web frameworks automatically handle the generation of the final redirection URL, using knowledge the web application has about the context it's running in. Normally this allows for things like transparently moving the web application from host to host (dev to test, or test to staging, etc) without having to re-specify every redirect in some configuration file or build a facility in the web application to allow 'smart' redirect writing. Since a web application can have potentially many redirects, this is a Good Thing(tm).
Those of you who read murder mysteries have probably already connected the dots here, but just to go all Agatha Christie on you I'll lay it out myself. The fact that a web application behind a hardware SSL accelerator cannot identify that it's running in an HTTPS/SSL context means that when redirects are automatically generated by a framework, the URLs are generated incorrectly. The scheme portion is generated as http, resulting in a page such as:
https://www.firepondondemand.com/app/blah.do?somestuff=whatever
redirecting to:
http://www.firepondondemand.com/foo/bar.do?baz=bat
There are two potential problems here. Either http traffic is not accepted by the web application, in which case the second URL fails to load, or http traffic is accepted but the person has moved from a secure context to an insecure context. Not only is this a potential problem for application security, Internet Explorer will pop up a nasty dialog saying that you've just been redirected to an insecure context and your life secrets may be leaking into the ether. Neither scenario is very good for customers.
Now that I have half my audience going "yeah yeah, get to the good stuff", I'll tell you how to fix this.
There's a solution which may work but which adds load to the network engineering team and to the accelerator itself. Because this problem is relatively common, the BigIP supports a profile setting known as Redirect Rewriting. If Redirect Rewrites are enabled on a profile used by your customer, their redirects might get automatically rewritten so as to change the http to https. This didn't work for Firepond, and since there is a solution at the webapp side, we didn't pursue why that is the case, but you should be aware of it as a potential solution for applications which have no way to fix this problem on their end. To be 100% clear, Redirect Rewrites are not normally turned on, and they may have an adverse effect on the application if redirects are generated which should not be rewritten automatically. Use With Caution.
The nicer solution, the one I'm writing this email about, is to somehow affect the framework's redirect URL generation facility so that it writes them correctly in the first place, without a ton of configuration. It turns out that this is possible in Tomcat, and since Tomcat is the embedded servlet engine for JBoss, Weblogic, and more, it becomes a transitive solution for most (all?) of our customers running in a Java environment.
As you might be aware, web applications sometimes run behind a proxy. The SSL accelerators we use aren't proxies, so it doesn't exactly spring to mind to treat them like proxies, but if we do our eyes naturally move to a portion of the Tomcat configuration regarding proxies. Specifically, you can specify the proxy's name, port, and most importantly the scheme the proxy uses to talk to clients. We can use this ability to configure Tomcat to behave as if we're running in an SSL context without actually incurring the CPU/configuration cost of running SSL directly on the web servers. Doing this is a very simple change:
1) Find the server.xml config file for your app server. It should mention Tomcat/Catalina stuff, if it doesn't you're in the wrong file.
2) Find the section of the file with a <Connector ...> tag referring to the port your app server runs on. In JBoss this is done with a variable, and in Tomcat the port is specified directly (usually as 8080). I haven't done this for Weblogic, but I imagine it's similar to JBoss. This tag should not be commented out, and many are. XML comments are the same as HTML, and read <!-- stuff commented out -->. So if that's wrapped around the tag you're looking at, you've got the wrong tag.
3) Once you've found it, add three attributes to this tag:
proxyName="www.yourcustomer.com"
proxyPort="443"
scheme="https"
4) Restart your app server and test that the change works. I reccomend using Firefox and the LiveHTTPHeaders plugin to see what's going on directly.
It'd be nice if you didn't have to set the proxyName, since this is a configuration setting you'll have to change depending on whether the application is running on a staging URL or not, but unfortunately Tomcat will not honor the scheme setting if you don't. You may also find some reference to setting secure="true" in Googling around about this problem. Don't do it. That tells Tomcat to really turn SSL on, at which point it starts to look for certs and keystores and just generally goes down the path we're trying to avoid with the SSL accelerator in the first place.
And that's it! If you have any questions/problems doing this sort of thing For Real, feel free to contact me via the usual routes and I'll be happy to help.
p.s. Some of you may notice a resemblance between this problem and a problem that some SOAP frameworks have automatically generating WSDL's. This is the same problem, and can be solved the same way. So, if your customer complains that their app is suddenly generating WSDL's with http endpoints when they should be https, you can probably fix it as I've described above. This is an issue with every Java-based SOAP framework I've used, and can also be worked around by hard-coding the WSDL. There are other reasons to hard-code your WSDL, so this might be acceptable, but often it's sub-optimal.
0 comments