views:

1679

answers:

14

I am developing a java web app using servlet, in order to prevent user from hitting the back button to see previous users' info, I have the following code :

      protected void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
      {        
        HttpSession session=request.getSession(true);

        response.setContentType("text/html");
        response.setHeader("Cache-Control","no-cache,no-store");
        response.setDateHeader("Expires",0);
        response.setHeader("Pragma","no-cache");

        ......

        //    if (!User_Logged_In)
        session.invalidate();
      }

Besides I also have the following code in the file : web/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;
......
<filter>
  <filter-name>ResponseHeaderFilter</filter-name>
  <filter-class>ResponseHeaderFilter</filter-class>
  <init-param>
    <param-name>Cache-Control</param-name>
    <param-value>private,no-cache,no-store</param-value>
   </init-param>
  <init-param>
    <param-name>Pragma</param-name>
    <param-value>no-cache</param-value>
   </init-param>
  <init-param>
    <param-name>Expires</param-name>
    <param-value>0</param-value>
   </init-param>
</filter>

</web-app>

And the ResponseHeaderFilter.java looks like this :

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ResponseHeaderFilter implements Filter
{
  FilterConfig fc;

  public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException
  {
    HttpServletResponse response=(HttpServletResponse)res;

    for (Enumeration e=fc.getInitParameterNames();e.hasMoreElements();)        // Set the provided HTTP response parameters
    {
      String headerName=(String)e.nextElement();
      response.addHeader(headerName,fc.getInitParameter(headerName));
    }
    chain.doFilter(req,response);                                              // Pass the request/response on
  }

  public void init(FilterConfig filterConfig)
  {
    this.fc=filterConfig;
  }

  public void destroy()
  {
    this.fc=null;
  }
}

So far it's still not working correctly. The back button will bring up a warning window saying the data has expired, it asks if the user wants to repost it. If you choose yes, it will still display the previous pages info. What am I doing wrong? What's the fix ?

Frank

+3  A: 

Breaking the back button is a cardinal sin of web development.

but you could try a bit of java script in the onload that refreshed the details according to the currently logged in session.

Omar Kooheji
Breaking the back button is only relevant within a single session. For example, I can't open a new browser window and hit the "back" button to go to the last website I visited.
sep332
+1  A: 

I'm not sure if I understand your problem exactly. Are you concerned about Person A logging off, Person B logs in from the same PC and browser instance, and then you want to prevent Person B from seeing whatever A was viewing?

If so, it should be sufficient to check the credentials of the user on every page load. Check that the current user is authorized to view the data being requested.

matt b
+11  A: 

How will hitting the back button cause the user to see another user's data? What is your use case? Is it designed for a public terminal, where each user submits data and then leaves? In this case, associate each input with a unique session id. Keep track of valid session ids in your server. Once the input is submitted, remove that session id from the valid ids. If it comes up again, then don't display the information.

Claudiu
I agree - it sounds like he's trying to solve a problem that shouldn't exist... running the session as a singleton or something?
GalacticCowboy
+9  A: 

Your problem is that you're trying to keep the client from seeing what's on his or her own computer. You can't keep them from looking at their browser cache. You can't keep them from disabling JavaScript (and thus your scripting code). You can't keep them from using a browser that doesn't observe that "repost" convention that you mention.

This is not a problem that can be solved with JavaScript or a server-side solution. That part of why "breaking the back button" is frowned upon: it doesn't actually solve anything.

catfood
Actually, you can turn caching off. Most browsers respect this, but it's not guaranteed.
sep332
As I mentioned in my post here, you can turn off caching but history may be treated differently by different user agents. The HTTP specification makes a distinction between the two but doesn't really define the concept of history as well as it defines caching.
laz
A: 

I had a similar problem in .Net. I added the following javascript to my logout page:

document.execCommand("ClearAuthenticationCache","false");

now if you press the back button you need to authenticate again.

MBoy
Have you considered that a malicious user could simply turn off Javascript?
Zarkonnen
+2  A: 

It sounds like your real problem is that the re-post works. That would probably be because you:

  1. are trusting credentials from the browser rather than the current session, or
  2. are not checking that the current session is allowed access the data represented by a key/identifier value sent from the browser

I recommend that after a user has logged in you never trust a user name submitted by the browser. Ideally use the security services of a framework like Spring Security but in their absence you can rely on HttpServletRequest.getUserPrincipal().

To make sure the current session is allowed access the data you could use an Access Control List mechanism provided by a framework such as Spring Security or include a WHERE OWNER=? clause in your database queries.

bmatthews68
A: 

If you're worried about someone seeing what was in a form in a previous page you could use a hidden form for the "real" post and use one that's just for display for the user. When the user submits the display form, you copy all of the fields to the hidden form, clear the display form, then submit the hidden one.

I agree with everyone else - fiddling with the back button this is a bad way to handle protecting information.

Diodeus
A: 

I'm not 100% sure this is a fix to your issue, as I don't fully understand how you would get another user's data using back. However, I know that for the web apps I develop I try to exclusively use Redirect After Post to avoid back button and refresh duplicate form submissions.

Instantsoup
A: 

Jeff Atwood described a way to prevent CSRF and XSRF attacks here.

You could use this technique to solve your "users seeing what they should not see" problem.

HuibertGill
A: 

Yes, I am developing a web app for a PC in public place, if user B hits the back button he might see user A's private info.

I was trying to use session id with servlet, but how to do it, any sample code ?

I also tried the following :

<Html>
<Head>...</Head>
<Body onLoad=document.execCommand("ClearAuthenticationCache","false")>
......
<script type="text/javascript">
  // Clear current credentials : Requires IE6 SP1 or later
  // document.execCommand("ClearAuthenticationCache");
    document.execCommand("ClearAuthenticationCache","false");
  </script>
......
</Html>

It works for IE but but Firefox.

Frank
+1  A: 

I'm not sure I understand your problem correctly, but it sounds like you are allowing rePOSTs.

One approach to prevent resubmission is to use tokens. Put a random token in the form and session. On submission check that the submitted token matches the token in the session

  • if it does, replace the token in the session with a fresh one and process the request
  • otherwise stop processing the request).
Steve Bosman
+1  A: 

All of the different browsers have different behaviors and quirks when it comes to how history relates to the cache and the various headers available to control it. Firefox 3 works differently from Firefox 2, re-displaying potentially sensitive data when a user clicks the back button in spite of using caching directives to prevent it. The best solution is to use a session cookie that is not persisted and inform the user of the need to close the browser window after logging out. Especially if they are at a public terminal. Painful, I know, but current browser offerings and the HTTP specification do not provide any mechanisms for dealing with browser history. History may be treated differently than caching by a user agent according to the HTTP specification. See 13.13 History Lists as defined in RFC 2616 Hypertext Transfer Protocol -- HTTP/1.1 for the problem and rationale.

laz
A: 

I think this is as much a user interface challenge as a coding problem. On top of whatever anti-caching techniques you employ, you need to make it clear to the user that they must hit a big, obvious "Logout" button (or equivalent) when they are done.

David Kolar
A: 

if this might help. This works for ASP, use an equivalent solution for other languages.

<% response.buffer = true%> <% Response.CacheControl = "no-cache" %> <% Response.AddHeader "Pragma", "no-cache" %> <% Response.Expires = -1 %>