Asp.net 使用WebApi、标识和安全使用cookie的MVC应用程序

Asp.net 使用WebApi、标识和安全使用cookie的MVC应用程序,asp.net,asp.net-mvc,cookies,asp.net-web-api,asp.net-identity,Asp.net,Asp.net Mvc,Cookies,Asp.net Web Api,Asp.net Identity,我有一个要求,让我的身份启用的MVC站点和WebApi使用cookies对站点和WebApi进行身份验证。任何处理过此问题的人都可能知道,这可能容易受到XSS攻击,因为常规登录cookie可能通过访问恶意页面发送到您的webapi方法 在web api中使用cookie的奇怪要求是问题的根源。有什么安全的方法吗 我有一个在AuthorizationFilter中使用表单身份验证的解决方案(发布在下面),但我希望利用身份框架的功能,例如声明和到处注销 using System; using Sys

我有一个要求,让我的身份启用的MVC站点和WebApi使用cookies对站点和WebApi进行身份验证。任何处理过此问题的人都可能知道,这可能容易受到XSS攻击,因为常规登录cookie可能通过访问恶意页面发送到您的webapi方法

在web api中使用cookie的奇怪要求是问题的根源。有什么安全的方法吗

我有一个在
AuthorizationFilter
中使用表单身份验证的解决方案(发布在下面),但我希望利用身份框架的功能,例如声明和到处注销

using System;
using System.Web.Http.Filters;
using System.Web.Http;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Security.Principal;
using System.Web;
using System.Web.Security;
using System.Collections.Generic;

namespace Filters
{

    /// <summary>
    /// An authentication filter that uses forms authentication cookies.
    /// </summary>
    /// <remarks>Use the *Cookie static methods to manipulate the cookie on the client</remarks>
    public class FormsAuthenticationFilter : Attribute, IAuthenticationFilter
    {

        public static long Timeout { get; set; }
        public static string CookieName { get; set; }

        public FormsAuthenticationFilter()
        {
            // Default Values
            FormsAuthenticationFilter.Timeout = FormsAuthentication.Timeout.Minutes;
            FormsAuthenticationFilter.CookieName = "WebApi";
        }


        public FormsAuthenticationFilter(long Timeout, string CookieName)
        {
            FormsAuthenticationFilter.Timeout = Timeout;
            FormsAuthenticationFilter.CookieName = CookieName;

        }

        public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {

            HttpRequestMessage request = context.Request;

            // Get cookie
            HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthenticationFilter.CookieName];

            //If no cookie then do nothing
            if (cookie == null)
            {
                return Task.FromResult(0);
            }

            //If empty cookie then raise error
            if (String.IsNullOrEmpty(cookie.Value))
            {
                context.ErrorResult = new AuthenticationFailureResult("Empty ticket", request);
                return Task.FromResult(0);
            }

            //Decrypt ticket
            FormsAuthenticationTicket authTicket = default(FormsAuthenticationTicket);

            try
            {
                authTicket = FormsAuthentication.Decrypt(cookie.Value);

            }
            catch (Exception)
            {
                context.ErrorResult = new AuthenticationFailureResult("Invalid ticket", request);
                return Task.FromResult(0);

            }

            //Check if expired

            if (authTicket.Expired)
            {
                context.ErrorResult = new AuthenticationFailureResult("Ticket expired", request);
                return Task.FromResult(0);

            }

            //If caching roles in userData field then extract
            string[] roles = authTicket.UserData.Split(new char[] { '|' });

            // Create the IIdentity instance
            IIdentity id = new FormsIdentity(authTicket);

            // Create the IPrinciple instance
            IPrincipal principal = new GenericPrincipal(id, roles);

            // Set the context user 
            context.Principal = principal;

            // Update ticket if needed (sliding window expiration)
            if ((authTicket.Expiration - DateTime.Now).TotalMinutes < (FormsAuthenticationFilter.Timeout / 2))
            {
                RenewCookie(authTicket);

            }

            return Task.FromResult(0);

        }

        public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {

            //Do nothing
            return Task.FromResult(0);

        }

        public bool AllowMultiple
        {
            get { return false; }
        }

        /// <summary>
        /// Renews the cookie on the client using the specified FormsAuthenticationTicket
        /// </summary>
        /// <param name="OldTicket">A still-valid but aging FormsAuthenticationTicket that should be renewed</param>
        /// <remarks></remarks>
        protected static void RenewCookie(FormsAuthenticationTicket OldTicket)
        {
            HttpContext.Current.Response.Cookies.Add(GetCookie(OldTicket.Name, OldTicket.UserData));

        }

        /// <summary>
        /// Sets the authentication cookie on the client
        /// </summary>
        /// <param name="UserName">The username to set the cookie for</param>
        /// <remarks></remarks>
        public static void SetCookie(String user, IList<string> roles)
        {

            HttpContext.Current.Response.Cookies.Add(GetCookie(user, string.Join("|", roles)));

        }

        /// <summary>
        /// Removes the authentication cookie on the client
        /// </summary>
        /// <remarks>Cookie is removed by setting the expires property to in the past, may not work on all clients</remarks>
        public static void RemoveCookie()
        {
            if ((HttpContext.Current.Response.Cookies[FormsAuthenticationFilter.CookieName] != null))
            {
                HttpContext.Current.Response.Cookies[FormsAuthenticationFilter.CookieName].Expires = DateTime.Now.AddDays(-1);
            }

        }

        private static HttpCookie GetCookie(string UserName, string UserData)
        {

            //Create forms auth ticket
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, UserName, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthenticationFilter.Timeout), false, UserData);

            //Create cookie with encrypted contents
            HttpCookie cookie = new HttpCookie(FormsAuthenticationFilter.CookieName, FormsAuthentication.Encrypt(ticket));
            cookie.Expires = DateTime.Now.AddMinutes(FormsAuthenticationFilter.Timeout);

            //Return it
            return cookie;

        }

        protected class AuthenticationFailureResult : IHttpActionResult
        {

            public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
            {
                this.ReasonPhrase = reasonPhrase;
                this.Request = request;
            }

            public string ReasonPhrase { get; set; }
            public HttpRequestMessage Request { get; set; }

            public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
            {
                return Task.FromResult(Execute());
            }

            private HttpResponseMessage Execute()
            {
                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                response.RequestMessage = Request;
                response.ReasonPhrase = ReasonPhrase;
                return response;
            }

        }

    }

}
使用系统;
使用System.Web.Http.Filters;
使用System.Web.Http;
使用System.Net.Http;
使用系统线程;
使用System.Threading.Tasks;
Net系统;
使用System.Security.Principal;
使用System.Web;
使用System.Web.Security;
使用System.Collections.Generic;
名称空间过滤器
{
/// 
///使用表单身份验证Cookie的身份验证筛选器。
/// 
///使用*Cookie静态方法操作客户端上的Cookie
公共类FormsAuthenticationFilter:属性,IAAuthenticationFilter
{
公共静态长超时{get;set;}
公共静态字符串CookieName{get;set;}
公共表单身份验证筛选器()
{
//默认值
FormsAuthenticationFilter.Timeout=FormsAuthentication.Timeout.Minutes;
FormsAuthenticationFilter.CookieName=“WebApi”;
}
公共表单身份验证筛选器(长超时,字符串CookieName)
{
FormsAuthenticationFilter.Timeout=超时;
FormsAuthenticationFilter.CookieName=CookieName;
}
公共任务AuthenticationAsync(HttpAuthenticationContext上下文,CancellationToken CancellationToken)
{
HttpRequestMessage请求=context.request;
//拿饼干
HttpCookie cookie=HttpContext.Current.Request.Cookies[FormsAuthenticationFilter.CookieName];
//如果没有饼干,那就什么也不做
if(cookie==null)
{
返回Task.FromResult(0);
}
//如果cookie为空,则引发错误
if(String.IsNullOrEmpty(cookie.Value))
{
context.ErrorResult=新身份验证失败结果(“空票证”,请求);
返回Task.FromResult(0);
}
//解密票据
FormsAuthenticationTicket authTicket=默认值(FormsAuthenticationTicket);
尝试
{
authTicket=FormsAuthentication.Decrypt(cookie.Value);
}
捕获(例外)
{
context.ErrorResult=新身份验证失败结果(“无效票证”,请求);
返回Task.FromResult(0);
}
//检查是否过期
如果(authTicket.Expired)
{
context.ErrorResult=新身份验证失败结果(“票证过期”,请求);
返回Task.FromResult(0);
}
//如果在userData字段中缓存角色,则提取
string[]roles=authTicket.UserData.Split(新字符[]{'|'});
//创建IIdentity实例
IIdentity id=新表单实体(authTicket);
//创建IPrinciple实例
i主要负责人=新的一般负责人(id、角色);
//设置上下文用户
context.Principal=Principal;
//如果需要,更新票据(滑动窗口到期)
if((authTicket.Expiration-DateTime.Now).TotalMinutes<(FormsAuthenticationFilter.Timeout/2))
{
更新Cookie(authTicket);
}
返回Task.FromResult(0);
}
公共任务ChallengeAsync(HttpAuthenticationChallengeContext,CancellationToken CancellationToken)
{
//无所事事
返回Task.FromResult(0);
}
公共布尔允许多个
{
获取{return false;}
}
/// 
///使用指定的FormsAuthenticationTicket续订客户端上的cookie
/// 
///仍有效但已过期的身份证,应续订
/// 
受保护的静态无效续订cookie(FormsAuthenticationTicket OldTicket)
{
HttpContext.Current.Response.Cookies.Add(GetCookie(OldTicket.Name,OldTicket.UserData));
}
/// 
///在客户端上设置身份验证cookie
/// 
///为其设置cookie的用户名
/// 
公共静态void SetCookie(字符串用户、IList角色)
{
HttpContext.Current.Response.Cookies.Add(GetCookie(用户,字符串,连接(“|”,角色));
}
/// 
///删除客户端上的身份验证cookie
/// 
///Cookie是通过将expires属性设置为“过去”来删除的,可能无法在所有客户端上运行
公共静态void RemoveCookie()
{
if((HttpContext.Current.Response.Cookies[FormsAuthenticationFilter.CookieName]!=null))
{
HttpContext.Current.Response.Cookies[FormsAuthenticationFilter.CookieName].Expires=DateTime.Now.AddDays(-1);
}
}
私有静态HttpCookie GetCookie(字符串用户名、字符串用户数据)
{
//创建表单身份验证票证
FormsAuthenticationTicket票证=新的FormsAuthenticationTicket(1,用户名,DateTime.Now,DateTime.Now.AddMinutes(FormsAuthenticationFilter.Timeout),false,用户数据);
//创建具有加密内容的cookie
HttpCookie cookie=新的HttpCookie(FormsAuthenticationFilter.CookieName,FormsAuthentication.Encrypt(票证));
饼干
public const string WebApiCookieAuthenticationType = "WebApiCookie";

public static CookieAuthenticationOptions CreateCookieAuthenticationOptions()
{

     return new CookieAuthenticationOptions
     {
        AuthenticationType = WebApiConfig.WebApiCookieAuthenticationType,
        AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive,
        CookieName = ".AspNet.WebApiCookie",
        CookiePath = "/api",
        ExpireTimeSpan = TimeSpan.FromDays(14),
        SlidingExpiration = true,
        LoginPath = new PathString("/api/auth"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(60),
                regenerateIdentity: (manager, user) => manager.CreateIdentityAsync(user, WebApiConfig.WebApiCookieAuthenticationType)
            ),
             OnApplyRedirect = ctx => {}
        }
    };

}
// Setup WebApi Cookie Authentication
app.UseCookieAuthentication(WebApiConfig.CreateCookieAuthenticationOptions());
// Ignore website auth
config.SuppressHostPrincipal();
config.Filters.Add(new HostAuthenticationFilter(WebApiCookieAuthenticationType));
[AllowAnonymous]
public async Task<IHttpActionResult> Authenticate(string userName, string password)
{

    // Get signIn manager
    var signInManager = HttpContext.Current.Request.GetOwinContext().Get<ApplicationSignInManager>();
    if (signInManager == null)
    {
        return BadRequest();
    }
    // Important!
    signInManager.AuthenticationType = WebApiConfig.WebApiCookieAuthenticationType;

    // Sign In
    var result = await signInManager.PasswordSignInAsync(userName, password, false, shouldLockout: true);
    if (result == SignInStatus.Success)
    {

        // Return
        return Ok();

    }

    // Failure
    return BadRequest();

}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
    if (this.AuthenticationType == DefaultAuthenticationTypes.ApplicationCookie)
    {
        return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    }
    else
    {
        return base.CreateUserIdentityAsync(user);
    }

}