Reputation: 5858
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?
Upvotes: 10
Views: 22413
Reputation: 528
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>
Upvotes: 0
Reputation: 63
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);
}
};
}
Upvotes: 3
Reputation: 530
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.
Upvotes: 5
Reputation: 5948
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
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());
}
}
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
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.
Upvotes: 1
Reputation: 74
I believe you are missing the security tag. Try adding:
<secure>false</secure>
Upvotes: -1