如何在.NET Core 3.1中防范中间人攻击、会话劫持与会话重放攻击
IdentityServer4 OIDC 过期会话ID绕过认证漏洞修复方案
漏洞根因
该问题核心是两个配置缺陷导致:
- IdentityServer4默认未开启过期授权数据的自动清理,已失效的会话ID、授权凭证未被标记为无效
- 客户端仅校验token本身的签名和过期时间,未同步校验服务端的会话状态,导致过期会话的ID仍可通过验证
1. IdentityServer4服务端修复方案
- 开启持久化授权存储与自动清理
生产环境替换内存存储为EF/Redis持久化存储,开启过期授权数据自动清理机制:
services.AddIdentityServer(options => { // 统一配置会话有效期 options.Authentication.CookieLifetime = TimeSpan.FromHours(2); options.Authentication.CookieSlidingExpiration = true; options.Validation.ValidateIssuer = true; }) // 配置持久化操作存储 .AddOperationalStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(Configuration.GetConnectionString("IdentityServerDb")); // 开启自动清理过期token、会话授权记录 options.EnableTokenCleanup = true; options.TokenCleanupInterval = 3600; // 每小时执行一次清理 }) // 其余身份配置省略
- 优先使用参考Token替代JWT Token
JWT是自包含凭证,默认不校验服务端状态,替换为参考Token后客户端每次验证都需要调用自省端点校验有效性,已失效会话对应的凭证会直接被拦截:
// 客户端配置处指定Token类型 new Client { ClientId = "your_client_id", AccessTokenType = AccessTokenType.Reference, // 其余客户端配置省略 }
- 可选JWT黑名单兼容方案
如果需要保留JWT自包含特性,可实现JWT黑名单机制:将撤销、过期会话对应的JWT的jti字段存入Redis,过期时间和JWT本身有效期一致,每次请求校验jti是否在黑名单中,存在则直接返回401。 - 主动清理失效会话
用户登出、修改密码、异地登录触发时,主动调用IPersistedGrantStore.RemoveAllAsync删除对应用户的所有授权记录,关联的会话ID会直接失效。
2. 业务客户端修复方案
- 新增会话有效性校验中间件
每次请求拿到会话ID后先校验服务端是否存在有效授权记录,不存在直接拦截:
app.Use(async (context, next) => { var sid = context.User?.FindFirst(JwtClaimTypes.SessionId)?.Value; if (!string.IsNullOrEmpty(sid)) { var grantStore = context.RequestServices.GetRequiredService<IPersistedGrantStore>(); var validGrants = await grantStore.GetAllAsync(new PersistedGrantFilter { SessionId = sid }); if (!validGrants.Any()) { context.Response.StatusCode = 401; await context.Response.WriteAsync("Invalid session"); return; } } await next(); });
- 开启OIDC会话生命周期绑定
配置OIDC中间件将会话有效期和Token有效期绑定,自动过期本地会话:
services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies", options => { options.ExpireTimeSpan = TimeSpan.FromHours(2); options.SlidingExpiration = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.HttpOnly = true; options.Cookie.SameSite = SameSiteMode.Strict; }) .AddOpenIdConnect("oidc", options => { options.Authority = "https://your-identityserver-domain"; options.ClientId = "your_client_id"; options.ResponseType = "code"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; // 绑定Token有效期到本地会话 options.UseTokenLifetime = true; options.Scope.Add("openid"); options.Scope.Add("profile"); });
3. 额外安全加固
- 全站强制启用TLS 1.2及以上版本HTTPS,避免会话ID在传输过程中被窃取,降低中间人攻击风险
- 新增会话IP绑定校验,同一会话ID如果出现跨地域IP突变,直接强制下线清理对应授权记录
- 定期审计会话授权日志,排查异常访问的会话ID
内容的提问来源于stack exchange,提问作者sachin bhatt
相关产品推荐
相关产品推荐

