.NET 8.0 ASP.NET Core部署IIS后Session Cookie无法解密问题
问题场景
将基于.NET 8.0的ASP.NET Core MVC应用部署到IIS 8.5(Windows Server 2012 R2)后,Session中间件持续抛出数百条警告:
https://example.com/Login: Error unprotecting the session cookie.
Logger: Microsoft.AspNetCore.Session.SessionMiddleware
Callsite: Microsoft.AspNetCore.Session.CookieProtection.Unprotect
Exception: System.Security.Cryptography.CryptographicException: The key {x-y-z} was not found in the key ring.
已完成的配置:
- 在Startup.cs中配置了Session参数,并启用
app.UseSession() - 启用了IIS应用池的用户配置文件加载,消除了DataProtection临时密钥仓库的警告
- 通过
IHttpContextAccessor将公告列表字符串写入Session,相关服务已注册
但警告仍存在,且提示的密钥不在IIS默认密钥路径C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys中。
解决方案
1. 显式配置DataProtection持久化密钥存储
默认情况下,DataProtection会将密钥存储在应用池身份的用户配置文件目录中,这个路径可能因应用池重启、身份变更而失效。显式指定一个固定的共享存储路径:
在Program.cs(或Startup.cs)中添加DataProtection配置:
using Microsoft.AspNetCore.DataProtection; var builder = WebApplication.CreateBuilder(args); // 配置DataProtection密钥存储到固定路径 builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"C:\AppDataProtectionKeys")) .SetApplicationName("YourUniqueAppName"); // 同一应用的所有实例使用相同名称,确保密钥共享 // 后续添加Session等其他服务配置 builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(50); options.Cookie.IsEssential = true; options.Cookie.HttpOnly = true; options.Cookie.SameSite = SameSiteMode.Strict; }); var app = builder.Build(); // 确保中间件顺序正确 app.UseRouting(); app.UseSession(); // 必须在UseRouting之后,UseAuthorization之前 app.UseAuthorization(); // 其他中间件及路由配置
创建C:\AppDataProtectionKeys文件夹,给应用池身份(如IIS AppPool\你的应用池名称)分配读取和写入权限。
2. 检查Session中间件顺序
Session中间件的位置错误会导致初始化异常,引发密钥问题。必须保证:
app.UseSession()在app.UseRouting()之后app.UseSession()在app.UseAuthorization()之前
3. 强制刷新客户端Session Cookie
用户浏览器中可能留存了用旧密钥加密的Session Cookie,导致服务器无法解密。可以通过修改Session Cookie名称强制用户重新生成:
services.AddSession(options => { // 原有配置 options.Cookie.Name = ".YourApp.NewSession"; // 修改为全新的Cookie名称 });
4. 验证应用池身份权限
确保应用池身份对以下路径拥有足够权限:
- 你指定的DataProtection密钥存储目录
- 应用程序根目录
C:\ProgramData\Microsoft\Crypto\RSA(若使用机器级密钥)
如果使用ApplicationPoolIdentity,在文件夹权限中添加IIS AppPool\你的应用池名称账户,分配读写权限。
5. 调整密钥生命周期(可选)
若密钥频繁轮换导致旧密钥被清理,可以延长密钥有效期:
builder.Services.AddDataProtection() .SetDefaultKeyLifetime(TimeSpan.FromDays(180)) // 设置密钥有效期为180天 .PersistKeysToFileSystem(new DirectoryInfo(@"C:\AppDataProtectionKeys")) .SetApplicationName("YourUniqueAppName");
内容的提问来源于stack exchange,提问作者dpant

