ASP.NET Core中明文Cookie仅适用于非敏感数据,敏感信息必须通过AddAuthentication().AddCookie()流程使用加密票据;明文Cookie无签名易被篡改,加密Cookie依赖IDataProtection密钥共享、HTTPS强制(Secure=true)及统一认证配置。

在 ASP.NET Core 中直接用 Response.Cookies.Append 写明文 Cookie 是最简单的方式,但不安全、不推荐用于敏感数据;真正需要保护的值(如用户 ID、权限标识)必须走加密 Cookie 认证流程,否则容易被篡改或窃取。
明文 Cookie 的读写:只适合非敏感临时数据
明文 Cookie 操作快、无依赖,但所有内容都在 HTTP 头里裸传,浏览器开发者工具一眼可见。它只适用于“记住用户名”“主题偏好”这类无害信息。
-
Response.Cookies.Append("theme", "dark", new CookieOptions { Expires = DateTime.Now.AddDays(7) })—— 写入时必须显式传CookieOptions,否则默认会话级(关闭浏览器即失效) -
Request.Cookies.TryGetValue("theme", out string theme)—— 读取前务必用TryGetValue,直接索引Request.Cookies["theme"]在键不存在时会抛KeyNotFoundException - 删除不是清空值,而是设过期时间早于当前:
Response.Cookies.Delete("theme", new CookieOptions { Expires = DateTime.Now.AddYears(-1) }) - 注意:明文 Cookie 不校验签名,客户端可任意修改值,服务端拿过来就用 —— 这是最大风险点
加密 Cookie 必须用 AddAuthentication().AddCookie() 流程
所谓“加密 Cookie”,本质是 ASP.NET Core 的 Cookie 认证中间件生成的带签名+加密的票据(ticket),不是你手动加密字符串再塞进 Cookie。它由框架自动处理序列化、签名、AES 加密、防重放等逻辑。
- 注册阶段必须在
Program.cs(.NET 6+)或Startup.ConfigureServices中调用:services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie() - 登录时不能手拼字符串,要用
SignInAsync写入 Claims:await HttpContext.SignInAsync(scheme, new ClaimsPrincipal(identity), props) - 生成的 Cookie 名默认是
.AspNetCore.Cookies,值是一长串 Base64 编码的加密票据,无法被人工解析或篡改 - 读取时不要去碰原始 Cookie 值,而应通过
User.Identity.IsAuthenticated和User.FindFirst("claimName")获取解密后的声明
CookieOptions.Secure 必须为 true(尤其生产环境)
CA5382 分析规则警告的根本原因:HTTP 明文传输的 Cookie 被抓包即得,Secure = true 强制浏览器只在 HTTPS 下发送该 Cookie,这是硬性安全底线。
- 开发时若没配 HTTPS,可临时设
SecurePolicy = CookieSecurePolicy.None,但上线前必须切回Always - 如果用了反向代理(如 Nginx),需确保代理转发了
X-Forwarded-Proto: https,并在Program.cs中启用前向头解析:app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto }) - 单独对某个 Cookie 设
Secure = true不够 —— 整个认证 Cookie 的配置必须统一控制,推荐在AddCookie时全局设定:options.Cookie.SecurePolicy = CookieSecurePolicy.Always
集群部署时,IDataProtectionProvider 密钥必须共享
多台服务器共用同一套 Cookie 认证,但每台机器默认用本地密钥签名,结果就是:用户在 A 服务器登录后,跳到 B 服务器时 User.Identity.IsAuthenticated 为 false —— 因为 B 无法验证 A 签的票据。
- 解决方案是把数据保护密钥存到共享存储,例如 Redis:
services.AddDataProtection().PersistKeysToStackExchangeRedis(...) - SQL Server 或 Azure Key Vault 也可,关键是所有实例初始化时拿到的是同一组密钥
- 切勿用
.SetDefaultKeyLifetime(TimeSpan.FromDays(90))之类操作覆盖默认轮换策略,密钥管理交给框架更稳妥 - 本地开发可用
.SetApplicationName("MyApp")统一命名,避免不同项目密钥冲突
真正难的不是写几行 Append 或 SignInAsync,而是理解“加密 Cookie”不是功能开关,而是一整套认证生命周期 —— 从密钥分发、HTTPS 保障、到集群一致性,漏掉任何一环,所谓的“加密”就形同虚设。


















