/// <summary> /// Validates the request against XSRF attack. /// </summary> /// <param name="sessionId">The session id embedded in the query string.</param> /// <returns> /// <c>true</c> if the request is safe. Otherwise, <c>false</c>. /// </returns> private bool ValidateRequestAgainstXsrfAttack(out string sessionId) { sessionId = null; // get the session id query string parameter string queryStringSessionId = this.requestContext.Request.QueryString[SessionIdQueryStringName]; // verify that the query string value is a valid guid Guid guid; if (!Guid.TryParse(queryStringSessionId, out guid)) { return(false); } // the cookie value should be the current username secured against this guid var cookie = this.requestContext.Request.Cookies[SessionIdCookieName]; if (cookie == null || string.IsNullOrEmpty(cookie.Value)) { return(false); } // extract the username embedded within the cookie // if there is any error at all (crypto, malformed, etc.), fail gracefully string usernameInCookie = null; try { byte[] encryptedCookieBytes = HttpServerUtility.UrlTokenDecode(cookie.Value); byte[] decryptedCookieBytes = MachineKeyUtil.Unprotect(encryptedCookieBytes, AntiXsrfPurposeString, "Token: " + queryStringSessionId); usernameInCookie = Encoding.UTF8.GetString(decryptedCookieBytes); } catch { return(false); } string currentUsername = GetUsername(this.requestContext); bool successful = string.Equals(currentUsername, usernameInCookie, StringComparison.OrdinalIgnoreCase); if (successful) { // be a good citizen, clean up cookie when the authentication succeeds var xsrfCookie = new HttpCookie(SessionIdCookieName, string.Empty) { HttpOnly = true, Expires = DateTime.Now.AddYears(-1) }; this.requestContext.Response.Cookies.Set(xsrfCookie); } sessionId = queryStringSessionId; return(successful); }
/// <summary> /// Requests the specified provider to start the authentication by directing users to an external website /// </summary> /// <param name="returnUrl"> /// The return url after user is authenticated. /// </param> public void RequestAuthentication(string returnUrl) { // convert returnUrl to an absolute path Uri uri; if (!string.IsNullOrEmpty(returnUrl)) { uri = UriHelper.ConvertToAbsoluteUri(returnUrl, this.requestContext); } else { uri = this.requestContext.Request.GetPublicFacingUrl(); } // attach the provider parameter so that we know which provider initiated // the login when user is redirected back to this page uri = uri.AttachQueryStringParameter(ProviderQueryStringName, this.authenticationProvider.ProviderName); // Guard against XSRF attack by injecting session id into the redirect url and response cookie. // Upon returning from the external provider, we'll compare the session id value in the query // string and the cookie. If they don't match, we'll reject the request.n string sessionId = Guid.NewGuid().ToString("N"); uri = uri.AttachQueryStringParameter(SessionIdQueryStringName, sessionId); // The cookie value will be the current username secured against the session id we just created. byte[] encryptedCookieBytes = MachineKeyUtil.Protect(Encoding.UTF8.GetBytes(GetUsername(this.requestContext)), AntiXsrfPurposeString, "Token: " + sessionId); var xsrfCookie = new HttpCookie(SessionIdCookieName, HttpServerUtility.UrlTokenEncode(encryptedCookieBytes)) { HttpOnly = true }; if (FormsAuthentication.RequireSSL) { xsrfCookie.Secure = true; } this.requestContext.Response.Cookies.Add(xsrfCookie); // issue the redirect to the external auth provider this.authenticationProvider.RequestAuthentication(this.requestContext, uri); }