Disable Browser Caching in JSF
Posted by turbomanage on August 8, 2006
Browser caching of page content has negative security implications when your application runs on shared terminals (like the public library). You can turn it off with this simple phase listener.
package sandbox; import javax.faces.context.FacesContext;import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.http.HttpServletResponse; public class CacheControlPhaseListener implements PhaseListener { |
I’ve now packaged this as a jar that you can just drop in to your JSF project. The jar includes a faces-config snippet so the phase listener automatically registers itself if the jar is present.
jsf-nocache-1.0.jar (JAR, 3 kB)
Ward said
Thanks for the code man, I am having some issues with the back button /JSF and this is exactly the code I need. Much appreciated…
Sushma said
Thanks a lot…. It works like a charm…
Lowster said
Worked a treat, thanks.
hermes said
I am having some issues with Firefox.
Sam said
do you have a jsf example to trigger this CacheControlPhaseListener ? thanks.
turbomanage said
Sam,
I’ve now packaged it in a jar and included a link to the download in this post. Just drop the jar under WEB-INF/lib for your application. There’s nothing else you have to do to enable it. If you use a proxy tool like Paros, you’ll be able to see the no-cache headers getting written for each request.
/dmc
Sam said
Hi:
I am using myfaces tobago. would there be any configuration need to do? where is the links to get the jar file? thanks again
Sam said
do I need to add the below config into my existing faces-config.xml? I tried your suggestion above and did not work. thanks agian
com.learnjsf.util.nocache.CacheControlPhaseListener
JR said
Interesting that this gets called but does not write into the response. I threw a logger in there to make sure that its getting called but the headers don’t show up in the response.
Any thoughts on this?
Thanks
SwappeR said
What about Firefox 1.5? The code doesn’t work for it, it works only for IE6. Is there any solution for Firefox?
Peter Sramka said
THERE IS A FLAW WITH THIS TECHNIQUE.
Here is a quote from the HTTP 1.1 specification describing the “no-cache” header:
no-cache
If the no-cache directive does not specify a field-name, then a
cache MUST NOT use the response to satisfy a subsequent request
without successful revalidation with the origin server. This
allows an origin server to prevent caching even by caches that
have been configured to return stale responses to client requests.
If the no-cache directive does specify one or more field-names,
then a cache MAY use the response to satisfy a subsequent request,
subject to any other restrictions on caching. However, the
specified field-name(s) MUST NOT be sent in the response to a
subsequent request without successful revalidation with the origin
server. This allows an origin server to prevent the re-use of
certain header fields in a response, while still allowing caching
of the rest of the response.
Note: Most HTTP/1.0 caches will not recognize or obey this
directive.
When this response header is used without any field-name, then the cache is still allowed to store the response. It just can not re-use that response “without successful revalidation with the origin server.” Therefore, the stated aim of preventing “negative security implications when your application runs on shared terminals (like the public library)” is not achieved, since sensitive data may still be store on the shared terminal.
Consider the use of the “no-store” header, which is more secure, but still not a guarantee of security. Here is a quote from the HTTP 1.1 specification describing the “no-store” header:
no-store
The purpose of the no-store directive is to prevent the
inadvertent release or retention of sensitive information (for
example, on backup tapes). The no-store directive applies to the
entire message, and MAY be sent either in a response or in a
request. If sent in a request, a cache MUST NOT store any part of
either this request or any response to it. If sent in a response,
a cache MUST NOT store any part of either this response or the
request that elicited it. This directive applies to both non-
shared and shared caches. “MUST NOT store” in this context means
that the cache MUST NOT intentionally store the information in
non-volatile storage, and MUST make a best-effort attempt to
remove the information from volatile storage as promptly as
possible after forwarding it.
Even when this directive is associated with a response, users
might explicitly store such a response outside of the caching
system (e.g., with a “Save As” dialog). History buffers MAY store
such responses as part of their normal operation.
The purpose of this directive is to meet the stated requirements
of certain users and service authors who are concerned about
accidental releases of information via unanticipated accesses to
cache data structures. While the use of this directive might
improve privacy in some cases, we caution that it is NOT in any
way a reliable or sufficient mechanism for ensuring privacy. In
particular, malicious or compromised caches might not recognize or
obey this directive, and communications networks might be
vulnerable to eavesdropping.
InterJSF said
I am getting the following error when I dropped the jar in my web-inf/lib directory -
[STDOUT] ERROR PhaseListenerManager – Exception in PhaseListener RENDER_RESPONSE(6) beforePhase.
java.lang.ClassCastException: org.jboss.portlet.JBossRenderResponse
at com.learnjsf.util.nocache.CacheControlPhaseListener.beforePhase(CacheControlPhaseListener.java:16)
Alain O'Dea said
What about scalability? Is it really wise to disable all HTTP caching? Any reasonable web framework should let you configure domain-aware HTTP caching to reduce unnecessary load on the app and datastore.
sue said
I use this code, half work, and half does not work.
My application: on the left side use tree for the menu, when I click the back button, the page is rollback, but the menu is not.
any idea?
Thanks,
Murtaza said
I was trying exactly the same concept using Servlet Filter and it was not working. Thank you.
Akram Badr said
I try to use this but i think it does not work correctly
for example if I have web site contain a login page and after login page main page contain menu on left hand site if I clicked on menu link 1 ==> you will navigate to page 1 then click menu link 2 ==> you will navigate to page 2 then use back you will get page 1 not ==> page has expired (which is not correct), if you use back again you will get page has expired
Any help please
turbomanage said
You might try adding some logging statements to verify that the phase listener is being invoked on the transition from page 1 to page 2. Or use a Firefox plugin like TamperData to verify that the no-cache headers are being set correctly. Also try other browsers.
Pradip said
Hey i’m facing the same problem.
i have scenario like
user goes to Search page , from there go to detail page , edit it, save it.
now if i do back…it works fine in Firefox which takes me to edit page.
but in IE it displays “page has expired”..
Jigar said
adding this jar into my project didnt work ..
it is same as when jar was not present..
when user clicks on sign out button he/she will be navigated to logoutpage where session will be destroyed..
and then he/she will be forwarded to home page ..
but as user clicks back button he gets all the pages..which he must not..
browser :firefox 3.0
Jigar said
it isnt working …
by just putting it into current project.
Year One Online said
I can tell that this is not the first time at all that you write about the topic. Why have you decided to write about it again?
p.s. Year One is already on the Internet and you can watch it for free.