将 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)

我在登录控制器中使用以下代码将用户 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 来恢复访问令牌并将其放入请求 headers 以便可以检索控制器以将经过身份验证的请求发送到 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));
    }
}

我还在 post 表单中使用 MVC ValidateAntiForgeryToken 过滤器来防止 CSRF 攻击。

我想知道这个解决方案是否足够安全?

如果是,我如何从令牌中检索角色和声明并在控制器上的授权过滤器中使用它们?

link

上有很好的解释

它建议将令牌存储在网络应用程序的 cookie 中 (HttpOnly+Secure+Encrypted),因为它们提供了额外的安全性。也由于使用现代 Web 框架来防止 CSRF 的简单性。 HTML5 Web Storage 易受 XSS 攻击,攻击面积较大,成功攻击后可影响所有应用程序用户。

当我第一次不得不将新的 Web API 集成到遗留应用程序中时,我不得不创建一些自定义身份验证功能。我尝试遵循本书中的指南:

Pro ASP.NET Web API 安全性:保护 ASP.NET Web API(.NET 中的专家之声)

作者:Badrinarayanan Lakshmiraghavan

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 来保护我自己的客户端令牌并实现我自己的身份验证中间件组件相当简单。这可能是 "dangerous",但所有 encryption/decryption 都由比我聪明的人负责,在我最近的项目中,我一直在使用遗留的自定义权限方案;所以这种方法有点值得。