Avoid back button on JSF web application

前端 未结 2 1840
伪装坚强ぢ
伪装坚强ぢ 2020-11-22 08:23

I am showing VERY sensitive data. After the user logs out from my server I don\'t want another user to be able to see the data hitting the Back button of the browser.

<
相关标签:
2条回答
  • 2020-11-22 08:39

    By default, the browser's back button does not send a HTTP request to the server at all. Instead, it retrieves the page from the browser cache. This is essentially harmless, but indeed confusing to the enduser, because s/he incorrectly thinks that it's really coming from the server.

    All you need to do is to instruct the browser to not cache the restricted pages. You can do this with a simple servlet filter which sets the appropriate response headers:

    @WebFilter
    public class NoCacheFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
    
            if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
                response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
                response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
                response.setDateHeader("Expires", 0); // Proxies.
            }
    
            chain.doFilter(req, res);
        }
    
        // ...
    }
    

    (do note that this filter skips JSF resource requests, whose caching actually needs to be configured separately)

    To get it to run on every JSF request, set the following annotation on the filter class, assuming that the value of the <servlet-name> of the FacesServlet in your webapp's web.xml is facesServlet:

    @WebFilter(servletNames={"facesServlet"})
    

    Or, to get it to run on a specific URL pattern only, such the one matching the restricted pages, e.g. /app/*, /private/*, /secured/*, or so, set the following annotation on the filter class:

    @WebFilter("/app/*")
    

    You could even do the very same job in a filter which checks the logged-in user, if you already have one.

    If you happen to use JSF utility library OmniFaces, then you could also just grab its CacheControlFilter. This also transparently takes JSF resources into account.

    See also:

    • Prevent user from seeing previously visited secured page after logout
    • Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
    • Is JSF 2.0 View Scope back-button safe?
    0 讨论(0)
  • 2020-11-22 08:53

    I also found another good solution.

    In faces-config.xml add

    <lifecycle>
        <phase-listener id="nocache">client.security.CacheControlPhaseListener</phase-listener>
    </lifecycle>
    

    And implement the following class:

    package client.security;
    
    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;
    
    @SuppressWarnings("serial")
    public class CacheControlPhaseListener implements PhaseListener
    {
        public PhaseId getPhaseId()
        {
            return PhaseId.RENDER_RESPONSE;
        }
    
        public void afterPhase(PhaseEvent event)        
        {
        }
    
        public void beforePhase(PhaseEvent event)
        {
           FacesContext facesContext = event.getFacesContext();
           HttpServletResponse response = (HttpServletResponse) facesContext
                    .getExternalContext().getResponse();
           response.addHeader("Pragma", "no-cache");
           response.addHeader("Cache-Control", "no-cache");
           // Stronger according to blog comment below that references HTTP spec
           response.addHeader("Cache-Control", "no-store");
           response.addHeader("Cache-Control", "must-revalidate");
           // some date in the past
           response.addHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT");
        }
    } 
    
    0 讨论(0)
提交回复
热议问题