将 WebAPI JWT 访问令牌作为加密的 FormsAuthenticationTicket 存储在 Response.Cookies 中是不是安全(在 asp.net mvc 中)
Posted
技术标签:
【中文标题】将 WebAPI JWT 访问令牌作为加密的 FormsAuthenticationTicket 存储在 Response.Cookies 中是不是安全(在 asp.net mvc 中)【英文标题】:Is it secure to store a WebAPI JWT access token as an encrypted FormsAuthenticationTicket in Response.Cookies (in asp.net mvc)将 WebAPI JWT 访问令牌作为加密的 FormsAuthenticationTicket 存储在 Response.Cookies 中是否安全(在 asp.net mvc 中) 【发布时间】:2016-04-14 23:18:57 【问题描述】:我在登录控制器中使用下面的代码将用户 JWT 访问令牌存储在响应 cookie 中
var returnedJwtToken = authenticationResponse.Content;
try
//Store a WebAPI JWT accesstoken in an FormsAuthenticationTicket userData
var ticket = new FormsAuthenticationTicket( 1,
login.UserName,
DateTime.Now,
DateTime.Now.Add(TimeSpan.FromSeconds(returnedJwtToken.ExpiresIn)),
login.RememberMe,
returnedJwtToken.AccessToken,
FormsAuthentication.DefaultUrl);
//Encrypt it
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
//Add it to Response.Cookies
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
Domain = FormsAuthentication.CookieDomain,
Path = FormsAuthentication.FormsCookiePath,
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL ;
Response.Cookies.Add(cookie);
然后我使用自定义的 MVC AuthorizeAttribute 来恢复访问令牌并将其放入请求标头中,以便可以在控制器上检索以将经过身份验证的请求发送到 WebAPI。它还为我的 MVC 应用程序控制器提供授权。
public class SiteAuthorizeAttribute : AuthorizeAttribute
protected override bool AuthorizeCore(HttpContextBase httpContext)
// var tokenHandler = new JwtSecurityTokenHandler();
HttpCookie authCookie =httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
//Extract the forms authentication cookie
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
HttpContext.Current.Request.Headers["AccessKey"] = authTicket.UserData;
// Create the IIdentity instance
IIdentity id = new FormsIdentity(authTicket);
// Create the IPrinciple instance
IPrincipal principal = new GenericPrincipal(id, null);
// Set the context user
httpContext.User = principal;
var accessKey= httpContext.Request.Headers["AccessKey"];
return (!string.IsNullOrWhiteSpace(accessKey));
我还在帖子表单中使用 MVC ValidateAntiForgeryToken 过滤器来防止 CSRF 攻击。
我想知道这个解决方案是否足够安全?
如果是,我如何从令牌中检索角色和声明并在控制器上的授权过滤器中使用它们?
【问题讨论】:
将它存储在会话中怎么样?您提供给客户存储的任何内容都可以在发送之前进行修改。将它放在会话中,您仍然可以在服务器端访问它以传递给您的 WebAPI。 你的意思是我应该在会话中存储cookie吗?像这样:Session.Add("AccessKey", cookie);
不是整个 cookie,只是 returnedJwtToken.AccessToken
。例如。 Session.Add("AccessKey", returnedJwtToken.AccessToken)
如何检索声明和角色?
使用FormsAuthenticationTicket有问题吗?我需要使用它的过期时间并记住我
【参考方案1】:
当我第一次需要将新的 Web API 集成到旧版应用程序中时,我必须创建一些自定义身份验证函数。我尝试遵循本书中的指导方针:
Pro ASP.NET Web API 安全性:保护 ASP.NET Web API(.NET 专家的声音)
巴德里纳拉亚南·拉克什米拉哈万
https://www.amazon.com/Pro-ASP-NET-Web-API-Security/dp/1430257822/ref=sr_1_3?keywords=securing+.net+web+api&qid=1565367785&s=gateway&sr=8-3
根据我对这本书的记忆,这些是处理客户端令牌时要牢记的要点(我相信这是对 Garg 先生文章的扩展):
1) 使用安全的 HttpOnly cookie(防止 MIM 或 XSS 劫持令牌)
2) 创建一个与每个请求都提交的 cookie 不同的令牌(防止 XRSF 伪造)。不同意味着即使恶意脚本要从 localStorage 获取未受保护的令牌,也无法生成包含所有必要身份验证数据的请求。
3) 令牌将在服务器上生成,并经过高度加密和签名。对于 .NET Framework,本书为此目的使用了 AuthenticatedAesCng 库。这可以防止用户盲目篡改和读取数据。
MVC 最有可能遵循这些原则,而 ValidateAntiForgeryToken 听起来像是完成了上面的第 2 点。
我确实尝试了一段时间在 .NET Framework 和其他来源中使用提供的身份验证方法。然而,我从来没有对它们感到满意,也不认为它们满足我的需求。所以我对你的具体情况不是很熟悉,但是我希望这会有所帮助。
目前我发现使用 .NET Core DataProtection API 来保护我自己的客户端令牌并实现我自己的身份验证中间件组件相当简单。这可能是“危险的”,但所有的加密/解密都由比我聪明的人负责,而且在我最近的项目中,我一直在使用遗留的自定义权限方案;所以这种方法有点值得。
【讨论】:
【参考方案2】:link上有一个很好的解释
它建议将令牌存储在 Web 应用程序的 cookie (HttpOnly+Secure+Encrypted) 中,因为它们提供了额外的安全性。也由于使用现代 Web 框架防止 CSRF 的简单性。 html5 Web Storage 易受 XSS 攻击,攻击面较大,攻击成功时会影响所有应用程序用户。
【讨论】:
我对此有点困惑。它指出来自您的域的 JS 可以读取 auth cookie,以便使用标头复制它(双重提交令牌 CSRF 保护)。但是,如果 cookie 是 HttpOnly,那么客户端上的 JS 在浏览器中运行时应该无法访问它。那么框架如何使用 HttpOnly cookie 做到这一点呢?以上是关于将 WebAPI JWT 访问令牌作为加密的 FormsAuthenticationTicket 存储在 Response.Cookies 中是不是安全(在 asp.net mvc 中)的主要内容,如果未能解决你的问题,请参考以下文章