10

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?

Community
  • 1
  • 1
jpganz18
  • 5,508
  • 17
  • 66
  • 115
  • What happened to the bounty on this question?? – Barett Feb 28 '16 at 02:50
  • 1
    I didnt accept any answer because none of them worked and the period for the bounty expired... – jpganz18 Feb 29 '16 at 14:31
  • "the filter works smoothly" doesn't mean the answer was helpful? If you don't award your bounties to people who are helping, you're breaking the bounty system and people won't be likely to help you in the future. Added a few notes to your reply below (which is IMO a different question). – Barett Mar 01 '16 at 21:05
  • 1
    it does, but doesnt set the cookie ... Im sorry if I didnt give you the bountie, you have to know, even if I didnt give it, the bounty is discounted from the points who offer the bounty, so, if I didnt give it, was because even if the filter worked nicely, the cookie didnt... – jpganz18 Mar 01 '16 at 21:07
  • Well, I'm not helping anymore, so we'll see how that works out for ya. – Barett Mar 09 '16 at 17:56

5 Answers5

5

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.

jakub.josef
  • 530
  • 4
  • 12
3

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);
        }
    };
}
1

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.

Community
  • 1
  • 1
Barett
  • 5,826
  • 6
  • 51
  • 55
  • 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 Feb 18 '16 at 22:30
  • 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? – jpganz18 Feb 18 '16 at 22:54
  • 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.) – Barett Mar 01 '16 at 21:04
0

With the help of ServletContextListener we have control at servlet at tomcat startup and shutdown. So here on tomcat startup we are setting the configuration of httponly.

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public final class ContextListener implements ServletContextListener {

    private ServletContext context = null;
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        this.context = null;
    }
    @Override
    public void contextInitialized(ServletContextEvent event) {
        this.context = event.getServletContext();
        this.context.getSessionCookieConfig().setHttpOnly(true);

    }
}

Abb beloww entry in web.xml

<listener>
<description>contextListener</description>
<listener-class>
        main.ContextListener 
    </listener-class>
 </listener>
Dipak Prajapati
  • 486
  • 5
  • 13
  • `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();` – Anand Rockzz May 16 '19 at 01:25
-1

I believe you are missing the security tag. Try adding:

<secure>false</secure>