.NET 7.0单页应用生产环境Session混淆问题排查求助
问题背景与现象
我开发了一个基于.NET 7.0的单页Web应用(核心为Index页面),包含多个局部视图,流程如下:
- 首次带参数调用Index时,先清除Session,控制器及服务从数据库加载数据并存入Session,再将ID返回客户端;
- 后续各局部视图通过Ajax回调服务器(部分带额外数据),从Session获取数据后调用服务和数据库获取更多信息,部分局部视图在页面加载时调用,部分在用户操作后触发。
该应用在本地及少量用户的测试服务器上运行正常,但在100人规模的生产环境中,偶尔会出现Session混淆问题:用户的局部视图(多为初始加载的视图)加载到其他用户的旧Session数据,每日发生数次。
注:仅在首次Index请求时(清除Session后)写入Session变量。
相关代码片段(program.cs)
try { var builder = WebApplication.CreateBuilder(args); builder.Host.UseSerilog(); builder.Services.Configure<AppSettings>(configuration); builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) .AddNegotiate() .AddCookie(); builder.Services.AddAuthorization(options => { // By default, all incoming requests will be authorized according to the default policy. options.FallbackPolicy = options.DefaultPolicy; }); builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); builder.Services....... builder.Services....... builder.Services....... builder.Services.AddHttpContextAccessor(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(3600); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; options.Cookie.SameSite = SameSiteMode.None; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.Name = "DiscoursClient.Session"; }); var app = builder.Build(); app.UseSerilogRequestLogging(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.Use(async (context, next) => { if (context.Request.Path == "/newcom/Index") { context.Session.Clear(); } await next(); }); app.UseRouting(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); } catch (Exception ex) { Log.Fatal(ex, "Application terminated unexpectedly"); } finally { Log.CloseAndFlush(); }
另外,出现问题的局部视图通过@Html.AjaxGrid调用(使用了第三方Grid包)。
疑问
- 可能的原因是什么?
- 我对架构的理解是否存在错误?
问题分析与可能原因
1. 中间件顺序错误
当前中间件顺序存在致命问题:app.UseSession()的位置以及自定义清除Session的中间件顺序不符合ASP.NET Core的规范。正确的中间件执行顺序要求:
UseSession必须放在UseRouting之后、端点映射之前;- 自定义操作Session的中间件必须在
UseSession之后执行,否则Session尚未初始化,context.Session.Clear()的操作无法生效,导致旧Session数据残留。
你现在的顺序会导致请求进入自定义中间件时,Session还未被激活,清除操作无效,后续请求复用了未被正确清理的Session容器。
2. 分布式内存缓存的局限性
你使用了AddDistributedMemoryCache(),这种缓存是进程内的:
- 如果生产环境是多服务器/多进程部署,且未启用粘性会话,用户请求会被分发到不同服务器,Session数据无法跨进程共享,容易出现数据混淆;
- 即使是单服务器,高并发场景下也可能出现Session ID复用或HttpContext上下文被错误共享的问题(比如服务中错误地将
HttpContext捕获到静态变量中)。
3. 并发请求的时序问题
初始加载的局部视图会在页面加载时自动发起Ajax请求,可能出现多个请求并发到达服务器的情况:用户首次访问Index的清除Session请求还未完成,后续Ajax请求已经发送,此时Session可能还未完成初始化或清理,导致请求复用了旧的Session数据。
4. Session清除逻辑的缺陷
当前的清除逻辑仅通过路径匹配判断是否清除Session,存在漏洞:
- 如果请求路径存在大小写差异、额外查询参数,会导致匹配失败,Session未被清除;
- 清除Session后未主动生成新的Session ID,客户端仍持有旧ID,后续请求可能复用旧的Session容器,读取到其他用户的数据。
架构层面的问题
你依赖Session存储用户核心数据的设计在高并发、分布式环境下存在先天缺陷:
- Session依赖Cookie传递Session ID,一旦Cookie被劫持或Session ID复用,就会导致数据混淆;
- 分布式内存缓存不适合生产环境的Session存储,应替换为Redis、SQL Server等真正的分布式缓存,确保Session数据跨服务器共享;
- 单页应用依赖Session缓存用户数据的设计不够健壮,建议将用户标识(如用户ID)存储在认证Cookie中,每次请求通过用户ID直接从数据库获取数据,彻底避免Session混淆问题,同时提升应用的可扩展性。
内容的提问来源于stack exchange,提问作者a.reure
相关产品推荐
相关产品推荐

