You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测用户关闭标签页?.NET+JS+jQuery栈会话安全漏洞求解

解决方案

核心问题根因

原有方案仅依赖beforeunload事件做标记写入,未判断是否仍有其他存活的同站标签,站内跳转时前序页面触发卸载事件写入登出标记,新页面加载后误判触发登出,才会出现偶发误触发问题。

推荐方案:基于Broadcast Channel的多标签存活检测

该方案针对现代浏览器兼容覆盖率达95%以上,完全规避beforeunload误判问题,核心逻辑是通过同站跨标签通信能力,每次页面卸载前先查询是否还有其他存活的同站标签,仅当最后一个站点标签关闭时才清除授权标记。

前端实现代码

所有站内页面引入以下JS逻辑即可,兼容jQuery运行环境:

// 初始化同站授权校验广播通道
const authChannel = new BroadcastChannel('site_auth_check');
let existAliveTab = false;

// 监听其他标签的通信消息
authChannel.onmessage = (e) => {
  switch(e.data.type) {
    // 收到存活查询,回复本标签存活
    case 'ping':
      authChannel.postMessage({type: 'pong'});
      break;
    // 收到其他标签的存活回复,标记存在活跃标签
    case 'pong':
      existAliveTab = true;
      break;
  }
};

// 页面加载时校验授权状态
setTimeout(() => {
  // 无其他活跃标签且当前标签无有效授权标记,触发登出
  if (!existAliveTab && !sessionStorage.getItem('auth_pass')) {
    window.location.href = '/logout.aspx';
  } else {
    // 写入当前标签授权标记,sessionStorage随标签关闭自动销毁
    sessionStorage.setItem('auth_pass', '1');
  }
}, 100);

// 页面卸载前校验是否为最后一个活跃标签
window.addEventListener('beforeunload', () => {
  existAliveTab = false;
  authChannel.postMessage({type: 'ping'});
  // 短时间等待回复
  const start = Date.now();
  while (Date.now() - start < 10) {}
  // 仅最后一个标签关闭时清除授权相关存储
  if (!existAliveTab) {
    sessionStorage.removeItem('auth_pass');
  }
  authChannel.close();
});

服务端登出接口实现(.NET aspx)

logout.aspx.cs代码如下:

using System;
using System.Web.Security;

public partial class logout : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // 销毁服务端会话
        Session.Abandon();
        // 清除表单认证Cookie
        if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
        {
            HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
            authCookie.Expires = DateTime.Now.AddDays(-1);
            Response.Cookies.Add(authCookie);
        }
        // 跳转到登录页
        Response.Redirect("login.aspx", true);
    }
}

降级兼容方案(兼容不支持Broadcast Channel的旧浏览器)

如果需要覆盖IE等旧浏览器,可通过localStorage的storage事件实现跨标签通信,逻辑和广播通道一致,仅通信方式替换为读写localStorage监听变化即可。同时可配合服务端心跳机制缩小会话暴露窗口:

  1. 前端每30秒发送一次心跳请求到heartbeat.aspx,服务端更新会话最后活跃时间
  2. 服务端设置超过2分钟未收到心跳则直接销毁当前会话,即使出现浏览器强制结束未触发卸载事件的情况,最多2分钟会话就会自动失效

额外安全优化建议

  • 给所有会话Cookie增加HttpOnly、Secure、SameSite=Strict属性,避免Cookie被窃取
  • 敏感操作(修改账号信息、支付等)额外增加二次身份校验,进一步降低风险

内容的提问来源于stack exchange,提问作者Peelz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:15:06