【发布时间】:2016-05-10 21:34:28
【问题描述】:
我需要让我的启用 Identity 的 MVC 站点与 WebApi 使用 cookie 来对站点和 Web api 进行身份验证。处理过此问题的任何人都可能知道这很容易受到 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;
}
}
}
}
【问题讨论】:
标签: asp.net asp.net-mvc cookies asp.net-web-api asp.net-identity