避免JSF Web应用程序上的后退button
我正在显示非常敏感的数据。 用户从我的服务器注销后,我不希望另一个用户能够看到数据击中浏览器的后退button。
我怎样才能做到这一点?
默认情况下,浏览器的后退button根本不会向服务器发送HTTP请求。 而是从浏览器caching中检索页面。 这基本上是无害的,但是对最终用户来说确实很混乱,因为他/她错误地认为它确实来自服务器。
所有你需要做的就是指示浏览器不caching受限制的页面。 你可以用一个简单的servletfilter来设置适当的响应头 :
@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); } // ... }
(请注意,此filter会跳过JSF资源请求, 实际上需要单独configuration其caching )
为了让它在每个JSF请求上运行,假设在你的webapp的web.xml
中的FacesServlet
的<servlet-name>
的值是facesServlet
,那么在filter类上设置下面的注解:
@WebFilter(servletNames={"facesServlet"})
或者,为了让它在一个特定的URL模式上运行,例如/app/*
, /private/*
, /secured/*
等与限制页面相匹配的设置,在filter类上设置以下注释:
@WebFilter("/app/*")
你甚至可以在一个filter中完成相同的工作,如果你已经有一个filter检查login的用户。
如果您碰巧使用JSF实用程序库OmniFaces ,那么您也可以只抓住它的CacheControlFilter
。 这也透明地将JSF资源考虑在内。
也可以看看:
- 防止用户在注销后看到先前访问的受保护页面
- 会话过期授权redirect在提交JSF表单时不起作用,页面保持不变
- JSF 2.0查看范围后退button安全吗?
我还发现了另一个好的解决scheme
在faces-config.xml中添加
<lifecycle> <phase-listener id="nocache">client.security.CacheControlPhaseListener</phase-listener> </lifecycle>
并实施以下课程:
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"); } }