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

如何解决Classic ASP.Net MVC网站的OAuth2重放攻击问题?

修复Classic ASP.NET MVC Okta OAuth2注销后Cookie重放漏洞的方案

一、服务器端会话跟踪验证

Classic ASP.NET没有现成的ITicketStore,但可以自行实现类似的服务器端会话校验逻辑,核心是让每个认证Cookie绑定一个服务器端记录的会话状态,注销时标记会话无效:

  1. 登录时绑定会话ID
    登录成功后,生成唯一会话ID,存入认证Claims和服务器端缓存(或数据库、Redis):
var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie);
var sessionId = Guid.NewGuid().ToString();
// 将会话ID加入Claims
identity.AddClaim(new Claim("ServerSessionId", sessionId));
// 服务器端缓存会话,有效期与Cookie一致
HttpRuntime.Cache.Insert(
    sessionId, 
    "Active", 
    null, 
    DateTime.Now.AddMinutes(30), 
    Cache.NoSlidingExpiration
);
// 完成登录
HttpContext.GetOwinContext().Authentication.SignIn(
    new AuthenticationProperties { IsPersistent = false }, 
    identity
);
  1. 注销时销毁服务器端会话
    注销操作中,不仅清除客户端Cookie,还要删除服务器端的会话记录:
public ActionResult Logout()
{
    var authManager = HttpContext.GetOwinContext().Authentication;
    var claimsIdentity = User.Identity as ClaimsIdentity;
    var sessionId = claimsIdentity?.FindFirst("ServerSessionId")?.Value;
    
    if (!string.IsNullOrEmpty(sessionId))
    {
        HttpRuntime.Cache.Remove(sessionId);
    }
    
    // 清除客户端Cookie
    authManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
    return RedirectToAction("Login", "Account");
}
  1. 全局请求校验会话有效性
    在Global.asax.cs的Application_AuthenticateRequest事件中,对每个已认证请求校验服务器端会话状态:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (User?.Identity?.IsAuthenticated == true)
    {
        var claimsIdentity = User.Identity as ClaimsIdentity;
        var sessionId = claimsIdentity?.FindFirst("ServerSessionId")?.Value;
        
        // 会话ID不存在或服务器端无记录,强制注销
        if (string.IsNullOrEmpty(sessionId) || HttpRuntime.Cache.Get(sessionId) == null)
        {
            var authManager = HttpContext.Current.GetOwinContext().Authentication;
            authManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            Response.Redirect("/Account/Login");
            Response.End();
        }
    }
}

二、同步Okta端会话注销

利用Okta的OAuth2注销端点,在应用注销时同时终止Okta端的用户会话,这样即使客户端留存旧Cookie,应用向Okta验证令牌时会被拒绝:

public ActionResult Logout()
{
    var authManager = HttpContext.GetOwinContext().Authentication;
    authManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
    
    // 构造Okta注销URL,需提前在Okta控制台配置允许的post_logout_redirect_uri
    var oktaDomain = "https://your-okta-domain.com";
    var clientId = "your-okta-client-id";
    var redirectUri = Url.Action("Login", "Account", null, Request.Url.Scheme);
    var logoutUrl = $"{oktaDomain}/oauth2/v1/logout?client_id={clientId}&post_logout_redirect_uri={Uri.EscapeDataString(redirectUri)}";
    
    return Redirect(logoutUrl);
}

三、增强Cookie安全属性

通过配置Cookie的安全属性,降低Cookie被窃取和重放的风险(需.NET Framework 4.7.2及以上支持SameSite):

在Startup.Auth.cs的Cookie认证配置中添加:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    // 禁止前端脚本访问Cookie
    CookieHttpOnly = true,
    // 仅HTTPS环境下发送Cookie
    CookieSecure = CookieSecureOption.Always,
    // 限制Cookie跨站发送
    CookieSameSite = SameSiteMode.Strict,
    // 缩短Cookie有效期,减少重放窗口
    ExpireTimeSpan = TimeSpan.FromMinutes(15),
    // 滑动刷新有效期
    SlidingExpiration = true
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:11:12