When you’re using SSL to secure browser – server communications it’s a good idea to also mark all the cookies you exchange as secure. This tells the browser to only sent the cookies back to the server over an SSL connection, protecting them against sniffing. In addition secure cookies can only be accessed by JavaScript loaded from a secure connection giving you additional protection against client side attacks. The best general overview of cookies I’ve found is HTTP cookies explained. Let’s look at typical production and development deployments using apache and jetty and see how to configure things. In production I want secure cookies but in development I want regular cookies and I don’t want to have to recompile the code going from development to production.

In production apache handles the SSL decoding and encoding for the https connection and serves any static content. It passes requests for dynamically generated content to jetty over http using mod_proxy. In development the browser connects directly to jetty over http which serves both static and dynamic content.
My first concern turned out to be rather silly, will the secure cookies actually pass through the apache proxy and make it to jetty? A simple look at the cookie spec shows that information about cookie expiry, path, domain and the secure flag is only present in the set-cookie header sent from the server to the browser. The information sent from browser to server is only the cookie name and value. The server knows nothing more about the cookie and so apache’s mod_proxy just passes all cookies along with the request when it proxies it.
There are three sets of cookies to consider, those set on the client, those set on the server by code you write and those set on the server by jetty on your behalf, in particular the session cookie. The first set is the easiest, all of the client side cookies are going to be set by code you wrote. Using the Cookies.setCookie(….) method you can set the secure flag for any cookie you create. To detect whether a secure connection is present for the current page, and therefore whether the flag should be set you can use “https:”.equals(Window.Location.getProtocol()). This will set the flag in production but not in development.
On the server the first difficulty comes in detecting that there is an https connection. By the time the request reaches jetty it’s over http. How do you distinguish then between the development and production cases? The solution is in two parts, first using apache to add a header to identify requests originally coming over https, and second using this information in jetty.
Part one is accomplished using the apache RequestHeader direction from the mod_headers module. In the https configuration for apache add
RequestHeader set X-Forwarded-Ssl true
Now each request arriving at jetty that has come through apache on an https connection will have the X-Forwarded-Ssl header set. This means that in the development situation the header will not be present, so no special configuration is needed to distinguish between development and production. In production the jetty instance is only available through the apache proxy so it’s not possible to set the header on a direct http connection to jetty and so attempt to access secure cookies over http.
In your code it would be possible to check the X-Forwarded-Ssl header directly, however, when we get to cookies set by jetty, which includes the JESSSIONID session cookie, you need a different solution.
The interesting bit here is how you actually find the information you need. I approached this from a few different angles, starting with searching. I found this page about configuring mod_proxy and jetty which pointed to extending SelectChannelConnector and overriding the customize method to set the scheme for an incoming request. While this doesn’t work it did get me thinking about the methods available on SelectChannelConnector. Then I went looking for the code that sets the session cookie. You can find this in the org.mortbay.jetty.servlet.AbstractSessionManager class in the getSessionCookie method. The line that sets whether or not the cookie is secure is
cookie.setSecure(requestIsSecure && getSecureCookies());
The getSecureCookies() method returns the value of a property of the session manager that can be set via configuration and requestIsSecure is a parameter to the getSessionCookie method.
The configuration changes needed to set the secureCookies property can be added to the jetty-web.xml file.
<Get name="sessionHandler">
<Get name="sessionManager">
<Set name="secureCookies">true</Set>
</Get>
</Get>
Tracing back through the code the requestIsSecure parameter originates from the isSecure() method on the javax.servlet.ServletRequest class.
So the remaining step is to have isSecure() return true when the X-Forwarded-Ssl header is set on the request. Some more investigation shows that isSecure() is implemented as a call to isConfidential(…) on AbstractConnector and this is where it ties back into the page about configuring mod_proxy and jetty which shows using a subclass of SelectChannelConnector. The solution I chose was to subclass SelectChannelConnector and override the isConfidential method
public boolean isConfidential(Request request) {
if (request.getHeader("X-Forwarded-Ssl") != null) {
return true;
} else {
return super.isConfidential(request);
}
}
With these two changes the JSESSIONID cookie produced by jetty is marked as secure in production and not in development with no additional configuration or flags needed to distinguish the two environments. For cookies created by code you write you can now check the isSecure() method on the request when creating the cookie.