/// <summary> /// Creates a new instance of a FormsAuthenticationCookieAnalyzer /// </summary> /// <param name="formsAuthenticationCookie">The formsAuthenticationCookie to inspect</param> /// <param name="requestPhase">The phase of the request procesisng lifecycle from which the analysis is being requested</param> /// <param name="saveToContext">Whether or not to save the result of the analysis to the HttpContext.Current.Items collection</param> public static RequestAnalysis AnalyzeRequest(HttpCookie formsAuthenticationCookie, RequestLifecyclePhase? requestPhase, bool saveToContext) { EnhancedSecurity.Initialize(); ContextInformation context = new ContextInformation(); FormsAuthenticationCookieAnalysis formsAuthenticationCookieResult = AnalyzeFormsAuthenticationCookie(formsAuthenticationCookie); FormsAuthenticationTicketAnalysis formsAuthenticationTicketResult; UserAuthenticationTicketAnalysis userAuthenticationTicketResult; if (UserAuthentication.Enabled) { formsAuthenticationTicketResult = AnalyzeFormsAuthenticationTicket(formsAuthenticationCookieResult, true, requestPhase); userAuthenticationTicketResult = AnalyzeServerAuthenticationTicket(context, formsAuthenticationCookieResult, formsAuthenticationTicketResult, UserAuthentication.EnforceClientHostAddressValidation); } else { formsAuthenticationTicketResult = AnalyzeFormsAuthenticationTicket(formsAuthenticationCookieResult, false, requestPhase); userAuthenticationTicketResult = new UserAuthenticationTicketAnalysis(); } RequestAnalysis result = new RequestAnalysis(context, formsAuthenticationCookieResult, formsAuthenticationTicketResult, userAuthenticationTicketResult); if (saveToContext) { string contextKey = "Analysis:" + requestPhase.ToString(); HttpContext.Current.Items[contextKey] = result; } return result; }
/// <summary> /// Retrieves the saved analysis for the request phase specified /// </summary> /// <param name="requestPhase">The phase of the request processing to request an analysis for</param> /// <returns>The RequestAnalysis at the phase requested or null of one is not available</returns> public static RequestAnalysis RetrieveAnalysis(RequestLifecyclePhase requestPhase) { string contextKey = "Analysis:" + requestPhase.ToString(); if (HttpContext.Current.Items.Contains(contextKey)) { RequestAnalysis result = HttpContext.Current.Items[contextKey] as RequestAnalysis; } return null; }
/// <summary> /// Perform analysis of the FormsAuthenticationTicket supplied /// </summary> /// <param name="cookieAnalysis">The result of the FormsAuthenticationCookie analysis</param> /// <param name="enforceServerAuthenticationTicketValidation">Indicates whether to enforce UserAuthenticationTicket validation</param> /// <returns>A FormsAuthenticationTicketAnalysis object containing the results of the analysis</returns> public static FormsAuthenticationTicketAnalysis AnalyzeFormsAuthenticationTicket(FormsAuthenticationCookieAnalysis cookieAnalysis, bool enforceServerAuthenticationTicketValidation, RequestLifecyclePhase? phase) { FormsAuthenticationTicketAnalysis analysis = new FormsAuthenticationTicketAnalysis(); FormsAuthenticationTicket ticket = cookieAnalysis.GetFormsAuthenticationTicket(); analysis.TicketExists = (ticket != null); if (analysis.TicketExists) { if (cookieAnalysis.HasValue && ticket != null) { DateTime netFramework2ReleaseDate = new DateTime(2006, 1, 22); analysis.FormsAuthenticationTicket = ticket; analysis.TicketExists = true; analysis.CookiePathMatches = (ticket.CookiePath == FormsAuthentication.FormsCookiePath); analysis.HasUserData = (!string.IsNullOrEmpty(ticket.UserData)); analysis.IsExpired = ticket.Expired || ticket.Expiration.CompareTo(DateTime.Now) < 0; analysis.IsIssueDateValid = (ticket.IssueDate.CompareTo(netFramework2ReleaseDate) > 0); analysis.IsNameValid = (!string.IsNullOrEmpty(ticket.Name)); // && ticket.Name == ContextInformation.ThreadCurrentPrincipalIdentityName && ticket.Name == ContextInformation.UserIdentityName); analysis.HasUserData = !string.IsNullOrEmpty(ticket.UserData); analysis.IsPersistenceValid = true; /* TODO: See how to check this in FormsAuthentication */ string guid = null; if (ticket.UserData != null && ticket.UserData.Length == UserAuthentication.HashAlgorithmStringLength + UserAuthentication.GuidStringLength + 1 && ticket.UserData[UserAuthentication.HashAlgorithmStringLength] == ';') { string[] parts = ticket.UserData.Split(';'); if (parts.Length == 2) { string hash = parts[0]; analysis.UserDataContainsHash = true; for (int i = 0; i < hash.Length; i++) { if (!((hash[i] >= 0x30 && hash[i] <= 0x39) /* 0-9 */ /* || (hash[i] >= 0x41 && hash[i] <= 0x46) A-F (lowercase only!) */ || (hash[i] >= 0x61 && hash[i] <= 0x66))) /* a-f */ { analysis.UserDataContainsHash = false; break; } } if (analysis.UserDataContainsHash) { analysis.TicketHash = hash; string actualHash = UserAuthentication.CalculateFormsAuthTicketHash(ticket); analysis.IsUserDataHashValid = (hash == actualHash); } guid = parts[1]; try { #pragma warning disable 168 Guid testGuidCreation = new Guid(guid); #pragma warning restore 168 analysis.ServerKey = parts[1]; analysis.UserDataContainsServerAuthenticationTicketKey = true; } catch (FormatException) { analysis.UserDataContainsServerAuthenticationTicketKey = false; } catch (OverflowException) { analysis.UserDataContainsServerAuthenticationTicketKey = false; } catch (ArgumentNullException) { analysis.UserDataContainsServerAuthenticationTicketKey = false; } } else { analysis.UserDataContainsHash = false; analysis.UserDataContainsServerAuthenticationTicketKey = false; } } else { analysis.UserDataContainsHash = false; analysis.UserDataContainsServerAuthenticationTicketKey = false; } if (!string.IsNullOrEmpty(guid)) { UserAuthenticationTicket serverAuthenticationTicket = UserAuthentication.Provider.GetTicket(guid); if (serverAuthenticationTicket != null) { analysis.UserDataServerAuthenticationTicketKeyFound = true; analysis.SetServerAuthenticationTicket(serverAuthenticationTicket); } else { analysis.UserDataServerAuthenticationTicketKeyFound = false; } } else { analysis.UserDataServerAuthenticationTicketKeyFound = false; } analysis.IsVersionValid = (ticket.Version == 2); analysis.IsValid = analysis.TicketExists && analysis.CookiePathMatches && !analysis.IsExpired && analysis.IsIssueDateValid && analysis.IsNameValid && analysis.IsPersistenceValid && analysis.IsVersionValid; /* && (!enforceServerAuthenticationTicketValidation || analysis.HasUserData) && (!enforceServerAuthenticationTicketValidation || analysis.UserDataContainsHash) && (!enforceServerAuthenticationTicketValidation || analysis.IsUserDataHashValid) && (!enforceServerAuthenticationTicketValidation || analysis.UserDataContainsServerAuthenticationTicketKey) && (!enforceServerAuthenticationTicketValidation || analysis.UserDataServerAuthenticationTicketKeyFound) && (!enforceServerAuthenticationTicketValidation || UserAuthenticationTicket != null); */ if (!analysis.IsValid) { analysis.IsMalicious = !analysis.CookiePathMatches || !analysis.IsPersistenceValid || !analysis.IsIssueDateValid || !analysis.IsNameValid || !analysis.IsVersionValid; /* if (!analysis.IsMalicious && enforceServerAuthenticationTicketValidation && !isEndRequest) { analysis.IsMalicious = !analysis.HasUserData || !analysis.UserDataContainsHash || !analysis.IsUserDataHashValid || !analysis.UserDataContainsServerAuthenticationTicketKey; } */ } } else { analysis.IsValid = false; analysis.IsMalicious = false; } } else { analysis.IsValid = false; analysis.IsMalicious = false; } return analysis; }