ChatGPT解决这个技术问题 Extra ChatGPT

防止用户在注销后看到以前访问过的安全页面

我要求最终用户在注销/注销后不能返回受限页面。但目前最终用户可以通过浏览器的后退按钮、访问浏览器历史记录甚至通过在浏览器的地址栏中重新输入 URL 来做到这一点。

基本上,我希望最终用户在退出后不能以任何方式访问受限页面。我怎样才能做到最好?我可以使用 JavaScript 禁用后退按钮吗?

使用请求后获取模式。谷歌它。

C
Community

您可以而且不应该禁用浏览器后退按钮或历史记录。这对用户体验很不利。有 JavaScript hack,但它们不可靠,并且在客户端禁用 JS 时也无法工作。

您的具体问题是请求的页面是从浏览器缓存加载的,而不是直接从服务器加载的。这本质上是无害的,但确实让最终用户感到困惑,因为他/她错误地认为它确实来自服务器。

您只需要指示浏览器缓存所有受限制的JSP 页面(因此不仅仅是注销页面/操作本身!)。这样,浏览器被迫从服务器而不是从缓存中请求页面,因此将执行服务器上的所有登录检查。您可以使用在 doFilter() 方法中设置 necessary response headersFilter 来执行此操作:

@WebFilter
public class NoCacheFilter implements Filter {

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

        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 映射到感兴趣的 url-pattern,例如 *.jsp

@WebFilter("*.jsp")

或者,如果您只想将此限制放在受保护的页面上,那么您应该指定一个涵盖所有这些受保护页面的 URL 模式。例如,当它们都在文件夹 /app 中时,您需要指定 /app/* 的 URL 模式。

@WebFilter("/app/*")

更重要的是,您可以在检查登录用户是否存在的同一 Filter 中完成这项工作。

测试前不要忘记清除浏览器缓存! ;)

也可以看看:

用于登录的身份验证过滤器和 servlet

如何在所有浏览器中控制网页缓存?


有时这还不够,我记得有这样的问题。浏览器只记得最后一页。但它可能是 IE6,我不记得了 :)
@Bozho:要么您提供了一组不完整的标头,要么浏览器的页面仍在其缓存中。
@Chris:适用于 Firefox 和所有其他浏览器。您的问题是在其他地方引起的。也许你忘了清除一些缓存?或者那些标题设置在错误的响应上?
@BalusC 我创建了一个单独的过滤器类来覆盖 doFilter() 方法。当我按下注销按钮时,它被重定向到一个 servlet,我在其中使会话无效。我不确定 doFilter() 方法如何在这里发挥作用。你能告诉我如何实现这个吗?如,正确的步骤。谢谢。
对我来说效果很好。在 sendRedirect(...)forward() 之后测试。
F
Fahim Parkar

如果您转发页面,Url Pattern 中的 *.jsp 将不起作用。尝试也包含您的 servlet。这将使您的应用程序免受此后退按钮问题的影响。


A
Ashraf Sada

在不禁用浏览器返回按钮的情况下执行此操作的最简单方法是将此代码添加到您不希望用户在注销后返回的页面的 page_load 事件中:

if (!IsPostBack)
    {
        if (Session["userId"] == null)
        {
            Response.Redirect("Login.aspx");
        }
        else
        {
        Response.ClearHeaders();
        Response.ClearContent();
        Response.Clear();
        Session.Abandon();
        Session.Remove("\\w+");
        Response.AddHeader("Cache-Control", "no-cache, no-store, max-age = 0, must-revalidate");
        Response.AddHeader("Pragma", "no-cache");
        Response.AddHeader("Expires", "0");
        }
    }

尽管您的答案很有用,但请发布与 OP 选择的编程语言相关的答案。您的 C# 解决方案对 OP 的 Java EE 项目没有帮助。
D
Dan

正确的方法是添加

Vary: Cookie

安全页面上的标题。当用户注销时,清除他们的会话 cookie。然后,当他们在注销后导航回来时,浏览器缓存将丢失。这还具有不完全破坏缓存的好处。


B
Bozho

您可以尝试告诉浏览器不要缓存主页(使用适当的标头 - Expires、Cache-Control、Pragma)。但不保证能正常工作。您可以做的是在页面加载时对服务器进行 ajax 调用,以检查用户是否已登录,如果没有 - 重定向。


但是,如果一个邪恶的头脑禁用了 JavaScript,这将不起作用,他仍然会看到该页面。
R
Raja Mahapatra

实现过滤器的另一种方法是在所有受保护的 JSP 或所有路径上设置“无缓存”过滤器。如果应用程序很小,并且您只想为特定页面自定义此属性,这可能是一个好主意。我们可以在每个不应缓存的安全 JSP 上添加以下 Java 片段:

<%
  response.addHeader("Pragma", "no-cache");
  response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  response.setDateHeader("Expires", 0);
%>

如果不在 JSP 上,这也可以在定义了路由并设置“HttpServletResponse”对象的标头的控制器中使用。


A
Aniket Warey

对我来说,问题是,我不想在所有页面上设置标题,所以我只是在单击注销时在页面上设置这个标题,它会清除与网站相关的所有内容:)

// Removes all site data
response.setHeader ("Clear-Site-Data", "\"cache\"");

请在此处阅读更多信息:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data