将WebAPI JWT访问令牌存储为Response.Cookies中的加密FormsAuthenticationTic



我在登录控制器上使用以下代码将用户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攻击。

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

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

当我第一次必须将一个新的Web API集成到遗留应用程序中时,我必须创建一些自定义的auth函数。我试着遵循这本书中的指导方针:

Pro ASP.NET Web API安全性:确保ASP.NET Web API的安全(.NET中的专家语音)

Badrinarayanan Lakshmiragavan

https://www.amazon.com/Pro-ASP-NET-Web-API-Security/dp/1430257822/ref=sr_1_3?keywords=securing+.net+web+api&qid=1565367785&s=网关&sr=8-3

根据我对这本书的记忆,在处理客户端令牌时,以下是需要记住的要点(我相信这是对Garg先生的文章的扩展):

1) 使用安全的HttpOnly cookie(防止MIM或XSS劫持令牌)

2) 创建一个不同于cookie的令牌,该cookie也随每个请求一起提交(防止XRSF伪造)。不同意味着,即使恶意脚本要从localStorage获取未受保护的令牌,也无法使用所有必要的身份验证数据生成请求。

3) 令牌将在服务器上生成,并进行强加密和签名。对于.NET Framework,本书为此使用了一个AuthenticatedAesCng库。这可以防止用户在读取数据的同时盲目篡改数据

MVC很可能遵循这些原则,ValidateAntiForgeryToken听起来就像是在完成上面的第2点。

一段时间以来,我确实尝试在.NET Framework和其他源中使用所提供的身份验证方法。然而,我从来没有适应过他们中的任何一个,也不认为他们满足我的需求。所以我不太熟悉你的具体情况,但我希望这会有所帮助。

目前,我发现使用.NET Core DataProtection API来保护我自己的客户端令牌并实现我自己的auth MiddleWare组件非常简单。这可能是"危险的",但所有的加密/解密都由比我聪明的人负责,在我最新的项目中,我一直在使用传统的自定义权限方案;因此,这种方法在一定程度上是值得的。

链接上有一个很好的解释

它建议将令牌存储在web应用程序的cookie(HttpOnly+Secure+Encrypted)中,因为它们提供了额外的安全性。此外,由于使用现代web框架保护CSRF的简单性。HTML5 Web存储易受XSS攻击,攻击面更大,成功攻击后会影响所有应用程序用户。

最新更新