PAYATHON 2026

Chrome 用户离开页面后 .ASPXAUTH cookie 丢失

支付阿杰

结论

.ASPXAUTH 很可能不是付款网站删除的。更常见的是以下两种情况:

  1. 登录时创建的是会话 Cookie。浏览器关闭或恢复会话后,不保证继续保留它。
  2. Cookie 仍保存在浏览器中,但付款回跳时受域名、路径、HTTPS 或跨站请求限制,没有随请求发送。

仅凭 Chrome 20.0.1132.47 这个版本号,无法认定问题来自浏览器缺陷。也不要把”关闭并重新打开 Chrome 后 Cookie 仍然存在”当作可靠依据。会话 Cookie 没有明确的持久化期限,Chrome 的会话恢复功能可能暂时保留它,但它仍不是永久 Cookie。

检查付款回调请求中的 Cookie 请求头,并核对回跳地址:

  • 登录地址和回跳地址是否使用相同的主机名,例如 www.example.com 和 example.com 并不相同。
  • 是否从 HTTPS 回到了 HTTP。
  • .ASPXAUTH 的 Domain、Path 和 Secure 属性是否允许浏览器在回跳地址上发送它。
  • 付款平台使用普通的 GET 跳转,还是通过跨站表单 POST 返回。
  • 浏览器中是否还能看到 .ASPXAUTH,但请求头中没有它。

服务端可以临时记录是否收到了 Cookie,但不要记录 Cookie 的实际值:

HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

if (authCookie == null)
{
    // 只记录缺失事实以及必要的请求信息,
    // 不要把认证 token 写入日志。
}

如果付款过程中允许用户关闭窗口、重启浏览器,或者会打开新的浏览器会话,就不该使用会话 Cookie。创建登录 Cookie 时,应将 isPersistent 设置为 true:

FormsAuthentication.SetAuthCookie(userName, true);

如果是否记住登录状态由用户决定,可以直接传入对应选项:

FormsAuthentication.SetAuthCookie(
    userName,
    model.RememberMe
);

如需精确控制过期时间,可以显式创建认证票据:

DateTime issuedAt = DateTime.Now;
DateTime expiresAt = issuedAt.AddHours(2);

FormsAuthenticationTicket ticket =
    new FormsAuthenticationTicket(
        1,
        userName,
        issuedAt,
        expiresAt,
        true,
        string.Empty,
        FormsAuthentication.FormsCookiePath
    );

string encryptedTicket = FormsAuthentication.Encrypt(ticket);

HttpCookie cookie = new HttpCookie(
    FormsAuthentication.FormsCookieName,
    encryptedTicket
);

cookie.HttpOnly = true;
cookie.Path = FormsAuthentication.FormsCookiePath;
cookie.Expires = expiresAt;

// 仅当站点全程使用 HTTPS 时启用。
cookie.Secure = true;

Response.Cookies.Add(cookie);

还要检查 web.config 中的 Forms Authentication 配置:

<authentication mode="Forms">
  <forms
    loginUrl="~/Account/LogOn"
    timeout="120"
    slidingExpiration="true"
    requireSSL="true"
    path="/" />
</authentication>

timeout 控制认证票据的有效期,但不会自动将通过 SetAuthCookie(userName, false) 创建的会话 Cookie 转为持久 Cookie。

检查域名、路径和 HTTPS

假设用户在以下地址登录:

https://www.example.com/

而付款平台返回的是:

https://example.com/payment/complete

仅属于 www.example.com 的 Cookie 不会发送给 example.com。最稳妥的处理方式,是让登录入口和付款回调使用完全相同的协议、主机名和端口。

还需注意:

  • Path=/account 的 Cookie 不会发送到 /payment/complete。
  • 带有 Secure 属性的 Cookie 不会通过 HTTP 发送。
  • 不要为了绕过问题随意扩大 Domain,尤其不要让不受信任的子域共享认证 Cookie。

现代浏览器还需要检查 SameSite

Chrome 20 所处的年代早于后来的 SameSite 默认策略,因此不能据此认定当时的问题由 SameSite 引起。但如果该系统现在仍在运行,而付款平台通过跨站 POST 返回,现代浏览器可能不会发送 SameSite=Lax 或配置不正确的认证 Cookie。

这类流程通常需要:

SameSite=None; Secure

旧版 ASP.NET MVC/.NET Framework 是否支持 SameSite,取决于实际的框架版本和补丁状态,不能假定 MVC1 自带完整支持。如果无法升级,应优先调整付款回跳流程,使其不依赖认证 Cookie,不要手工拼接可能不兼容的 Cookie 属性。

付款结果不要只依赖 .ASPXAUTH

即使将 Cookie 改为持久 Cookie,付款确认也不应完全依赖用户是否仍处于登录状态。更可靠的流程是:

  1. 跳转到付款平台前创建本地订单,并生成不可预测的关联标识。
  2. 将订单号或签名后的 state 随付款请求发送。
  3. 回跳时根据该标识查找订单。
  4. 通过付款平台的服务端通知或查询接口验证支付状态。
  5. 即使用户 Cookie 缺失,也要完成订单入账,再要求用户重新登录查看结果。

不要直接信任通过未经签名的 URL 参数传入的用户 ID、金额或”支付成功”标记。

注意事项

  • 会话恢复后 Cookie 仍然存在,只是浏览器行为,并不代表浏览器承诺持久保存会话 Cookie。
  • 浏览器插件或隐私设置确实可能清理 Cookie,但没有复现证据时,不应将其视为主要原因。
  • 不要在日志、查询字符串或错误页面中输出 .ASPXAUTH 的值。
  • 延长认证有效期会增加 Cookie 被窃取后的风险,应同时使用 HTTPS、HttpOnly、合理的过期时间和重新认证机制。
  • 排查时,应按照浏览器版本、回跳方法、回跳主机名以及是否收到 Cookie 请求头分类,不要只统计用户最终是否仍处于登录状态。

备注:内容仅供参考。