Cookie http only with spring security and servlet 2.5?

18,557

Solution 1

I hate XML configuration, so i spend some time for find non-XML solution.

Since Spring Security 1.3 you can use

server.session.cookie.http-only=true
server.session.cookie.secure=true

in your application.properties file.

Maybe there is a way to set this using pure Java Configuration, but i can't find them.

Solution 2

We ran across this issue recently. I tried the property settings for http-only, which worked locally, but not when we deployed to our test env. It's possible there were some default settings in the env overriding those local settings. What worked was to set the properties in a Spring config file:

@Bean
public ServletContextInitializer servletContextInitializer() {
    return new ServletContextInitializer() {
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE));
            SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
            sessionCookieConfig.setHttpOnly(true);
            sessionCookieConfig.setSecure(true);
        }
    };
}

Solution 3

The context.xml changes mentioned by javagc will only reconfigure your session cookie.

To change all of your cookies, you have 2 options:

Option 1) Update your application code to add cookies using a more secure method. Example: https://stackoverflow.com/a/30488471/95674

Option 2) You can configure a servlet filter to change ALL (other) cookies coming through the system. Add these 2 classes into the appropriate package in your WAR. Then update your web.xml as detailed below.

There is a simpler example of Option 2 listed on the OWASP site, if you are willing to add a dependency on the OWASP libraries. That is located here: https://www.owasp.org/index.php/HttpOnly#Using_Java_to_Set_HttpOnly

Response Wrapper

This adds the http only flag to all cookies on the wrapped response.

public class HttpOnlyResponseWrapper extends HttpServletResponseWrapper {

 public HttpOnlyResponseWrapper(HttpServletResponse res) {
   super(res);
 }

 public void addCookie(Cookie cookie) {
   StringBuilder header = new StringBuilder();
   if ((cookie.getName() != null) && (!cookie.getName().equals(""))) {
     header.append(cookie.getName());
   }
   if (cookie.getValue() != null) {
     // Empty values allowed for deleting cookie
     header.append("=" + cookie.getValue());
   }

   if (cookie.getVersion() == 1) {
     header.append(";Version=1");
     if (cookie.getComment() != null) {
       header.append(";Comment=\"" + cookie.getComment() + "\"");
     }
     if (cookie.getMaxAge() > -1) {
       header.append(";Max-Age=" + cookie.getMaxAge());
     }
   } else {
     if (cookie.getMaxAge() > -1) {
       Date now = new Date();
       now.setTime(now.getTime() + (1000L * cookie.getMaxAge()));
       SimpleDateFormat cookieFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz");
       header.append(";Expires=" + cookieFormat.format(now));
     }
   }

   if (cookie.getDomain() != null) {
     header.append(";Domain=" + cookie.getDomain());
   }
   if (cookie.getPath() != null) {
     header.append(";Path=" + cookie.getPath());
   }
   if (cookie.getSecure()) {
     header.append(";Secure");
   }
   header.append(";httpOnly");
   addHeader("Set-Cookie", header.toString());
 }
}

Filter

This Filter wraps configured responses in the above wrapper.

package yourpackage;

@WebFilter(filterName = "HttpOnlyFilter", urlPatterns = {"/*"})
public class HttpOnlyFilter implements Filter {
 private FilterConfig config;

 @Override
 public void destroy() {
   this.config = null;
 }

 @Override
 public void doFilter(ServletRequest req, ServletResponse res,
     FilterChain chain) throws IOException, ServletException {

   HttpOnlyResponseWrapper hres = new HttpOnlyResponseWrapper((HttpServletResponse)res);
   chain.doFilter(req, hres);
 }

 public FilterConfig getFilterConfig() {
   return this.config;
 }

 @Override
 public void init(FilterConfig config) throws ServletException {
   this.config = config;
 }
}

Adapted (WARNING: NOT an exact copy!) from source: http://sylvanvonstuppe.blogspot.com/2007/07/servlet-filter-for-httponly.html

web.xml

One last detail: ONLY IF you have annotation scanning turned OFF in your system like this:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         version="2.5" ***metadata-complete="true"***>
</web-app> 

Then you will need to manually configure the above Filter in your web.xml file, like this:

<filter>
    <filter-name>HttpOnlyFilter
    <filter-class>yourpackage.HttpOnlyFilter
</filter>
<filter-mapping>
    <filter-name>HttpOnlyFilter
    <url-pattern>/*
</filter-mapping>

If your app scans annotations (which is the default), the web.xml part is not necessary.

Share:
18,557
jpganz18
Author by

jpganz18

Updated on July 20, 2022

Comments

  • jpganz18
    jpganz18 almost 2 years

    I want to make my cookie secure and http request only.

    Ive seen many post like this and seem to work fine, but using configuration files and servlet +3.

    What I basically want to do is to set my cookie http only and (if possible) ssl only as well.

    So far I added this to my web.xml

        <session-config>
            <session-timeout>60</session-timeout>
            <cookie-config>
                <http-only>true</http-only>
            </cookie-config>
            <tracking-mode>COOKIE</tracking-mode>
        </session-config>
    

    doesnt do anything, as far as I was reading, I also have to configure my servlet.xml to enable this feature, but I dont know how...

    Any idea how to do this?

    EDIT:

    Since I am using servlets 2.5 the xml configuration is not an option, maybe a filter?

  • jpganz18
    jpganz18 about 8 years
    Thanks, but this should not make any difference on the configuration
  • jpganz18
    jpganz18 about 8 years
    Hello, I saw the first option, but have no idea where to se it... is it the best approach? I saw the class... but , I add it to a filter?
  • jpganz18
    jpganz18 about 8 years
    the filter works smoothly! just wondering, how can I set the domain name or the secure = true if not using the xml configuration anymore? or just hardcoding them into the class?
  • Barett
    Barett about 8 years
    The XML configuration is only for the session cookie; it does not apply to all cookies set by your application. If you want to set the domain or secure values for cookies set by your app, you'll need to set them on the cookie itself. I've used a subclass of Cookie to do this in the past. (public class MyCookie extends Cookie, sets default values for domain/secure in the constructor. Add getters & setters that call super for everything, then make sure everyone uses this instead of Cookie.)
  • Anand Rockzz
    Anand Rockzz about 5 years
    java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener at event.getServletContext().getSessionCookieConfig();
  • Khoa Phung
    Khoa Phung almost 5 years
    These configurations is deprecated