I am using ABCPDF.net to render my HTML to PDF pages, but I want to protect these using the current authenticated session. However, the request to get the HTML to render the PDF doesnt carry over the session, but creates a new one. I am using ASP.NET Membership, and passwigin the session ID and creating a cookie on the ASP.NET request.
var sessionId = HttpUtility.ParseQueryString(Url)["sid"];
if(sessionId != null)
{
doc.HtmlOptions.HttpAdditionalHeaders = string.Format("Cookie:
ASP.NET_SessionId={0}", sessionId);
}
I read this in ABCPDF.net documentation and am doing just that, but the request always uses a different session.
httpadditionalheaders
Do I need to pass something else, or can I do something else?
Fixed it by sending the auth cookie in the URL, and updating the cookie.
Url To Call
Url.ActionAbsolute(MVC.Events.Pools(eventId).AddRouteValue(FormsAuthentication.FormsCookieName, Request.Cookies[FormsAuthentication.FormsCookieName].Value)
Global.asax
protected void Application_BeginRequest()
{
try
{
string auth_cookie_name = FormsAuthentication.FormsCookieName;
if (HttpContext.Current.Request.Form[FormsAuthentication.FormsCookieName] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[FormsAuthentication.FormsCookieName]);
}
else if (HttpContext.Current.Request.QueryString[FormsAuthentication.FormsCookieName] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[FormsAuthentication.FormsCookieName]);
}
}
catch
{
}
}
void UpdateCookie(string cookieName, string cookieValue)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookieName);
if (cookie == null)
{
cookie = new HttpCookie(cookieName);
HttpContext.Current.Request.Cookies.Add(cookie);
}
cookie.Value = cookieValue;
HttpContext.Current.Request.Cookies.Set(cookie);
}
Related
I have created an ASP.Net Web Forms application using Visual Studio 2013 and I am using .NET Framework 4.5. I want to make sure my site is secure from Cross-Site Request Forgery (CSRF), I have found many articles talking about how this feature is implemented on MVC apps, but very few talking about Web Forms. On this StackOverflow question one comment states that
"This is an old question, but the latest Visual Studio 2012 ASP.NET
template for web forms includes anti-CSRF code baked into the master
page. If you don't have the templates, here's the code it
generates:..."
My master page does not contain the code mentioned in that answer. Is it really included in new applications? If not, what is the best way to add it?
You could try the following. In the Web-Form add:
<%= System.Web.Helpers.AntiForgery.GetHtml() %>
This will add a hidden field and a cookie. So if you fill out some form data and post it back to the server you need a simple check:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
AntiForgery.Validate(); // throws an exception if anti XSFR check fails.
}
AntiForgery.Validate(); throws an exception if anti XSFR check fails.
ViewStateUserKey & Double Submit Cookie
Starting with Visual Studio 2012, Microsoft added built-in CSRF protection to new web forms application projects. To utilize this code, add a new ASP .NET Web Forms Application to your solution and view the Site.Master code behind page. This solution will apply CSRF protection to all content pages that inherit from the Site.Master page.
The following requirements must be met for this solution to work:
All web forms making data modifications must use the Site.Master page.
All requests making data modifications must use the ViewState.
The web site must be free from all Cross-Site Scripting (XSS) vulnerabilities. See how to fix Cross-Site Scripting (XSS) using Microsoft .Net Web Protection Library for details.
public partial class SiteMaster : MasterPage
{
private const string AntiXsrfTokenKey = "__AntiXsrfToken";
private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
private string _antiXsrfTokenValue;
protected void Page_Init(object sender, EventArgs e)
{
//First, check for the existence of the Anti-XSS cookie
var requestCookie = Request.Cookies[AntiXsrfTokenKey];
Guid requestCookieGuidValue;
//If the CSRF cookie is found, parse the token from the cookie.
//Then, set the global page variable and view state user
//key. The global variable will be used to validate that it matches
//in the view state form field in the Page.PreLoad method.
if (requestCookie != null
&& Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
{
//Set the global token variable so the cookie value can be
//validated against the value in the view state form field in
//the Page.PreLoad method.
_antiXsrfTokenValue = requestCookie.Value;
//Set the view state user key, which will be validated by the
//framework during each request
Page.ViewStateUserKey = _antiXsrfTokenValue;
}
//If the CSRF cookie is not found, then this is a new session.
else
{
//Generate a new Anti-XSRF token
_antiXsrfTokenValue = Guid.NewGuid().ToString("N");
//Set the view state user key, which will be validated by the
//framework during each request
Page.ViewStateUserKey = _antiXsrfTokenValue;
//Create the non-persistent CSRF cookie
var responseCookie = new HttpCookie(AntiXsrfTokenKey)
{
//Set the HttpOnly property to prevent the cookie from
//being accessed by client side script
HttpOnly = true,
//Add the Anti-XSRF token to the cookie value
Value = _antiXsrfTokenValue
};
//If we are using SSL, the cookie should be set to secure to
//prevent it from being sent over HTTP connections
if (FormsAuthentication.RequireSSL &&
Request.IsSecureConnection)
{
responseCookie.Secure = true;
}
//Add the CSRF cookie to the response
Response.Cookies.Set(responseCookie);
}
Page.PreLoad += master_Page_PreLoad;
}
protected void master_Page_PreLoad(object sender, EventArgs e)
{
//During the initial page load, add the Anti-XSRF token and user
//name to the ViewState
if (!IsPostBack)
{
//Set Anti-XSRF token
ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
//If a user name is assigned, set the user name
ViewState[AntiXsrfUserNameKey] =
Context.User.Identity.Name ?? String.Empty;
}
//During all subsequent post backs to the page, the token value from
//the cookie should be validated against the token in the view state
//form field. Additionally user name should be compared to the
//authenticated users name
else
{
//Validate the Anti-XSRF token
if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
|| (string)ViewState[AntiXsrfUserNameKey] !=
(Context.User.Identity.Name ?? String.Empty))
{
throw new InvalidOperationException("Validation of " +
"Anti-XSRF token failed.");
}
}
}
}
Source
When you create a new 'Web Form Application' project in VS 2013, the site.master.cs will automatically include the XSRF/CSRF code in the Page_Init section of the class. If you still dont get the generated code, you can manually Copy + Paste the code. If you are using C#, then use the below:-
private const string AntiXsrfTokenKey = "__AntiXsrfToken";
private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
private string _antiXsrfTokenValue;
protected void Page_Init(object sender, EventArgs e)
{
// The code below helps to protect against XSRF attacks
var requestCookie = Request.Cookies[AntiXsrfTokenKey];
Guid requestCookieGuidValue;
if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
{
// Use the Anti-XSRF token from the cookie
_antiXsrfTokenValue = requestCookie.Value;
Page.ViewStateUserKey = _antiXsrfTokenValue;
}
else
{
// Generate a new Anti-XSRF token and save to the cookie
_antiXsrfTokenValue = Guid.NewGuid().ToString("N");
Page.ViewStateUserKey = _antiXsrfTokenValue;
var responseCookie = new HttpCookie(AntiXsrfTokenKey)
{
HttpOnly = true,
Value = _antiXsrfTokenValue
};
if (FormsAuthentication.RequireSSL && Request.IsSecureConnection)
{
responseCookie.Secure = true;
}
Response.Cookies.Set(responseCookie);
}
Page.PreLoad += master_Page_PreLoad;
}
protected void master_Page_PreLoad(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Set Anti-XSRF token
ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
ViewState[AntiXsrfUserNameKey] = Context.User.Identity.Name ?? String.Empty;
}
else
{
// Validate the Anti-XSRF token
if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
|| (string)ViewState[AntiXsrfUserNameKey] != (Context.User.Identity.Name ?? String.Empty))
{
throw new InvalidOperationException("Validation of Anti-XSRF token failed.");
}
}
}
You could use below piece of code, which will check the request where it is coming from
if ((context.Request.UrlReferrer == null || context.Request.Url.Host != context.Request.UrlReferrer.Host))
{
context.Response.Redirect("~/error.aspx", false);
}
It works great for me!!!
I detect session expiration with:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (null != filterContext.HttpContext.Session)
{
// Check if we have a new session
if (filterContext.HttpContext.Session.IsNewSession)
{
string cookie = filterContext.HttpContext.Request.Headers["Cookie"];
// Check if session has timed out
if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))
{
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
redirectTargetDictionary.Add("action", "SessionExpired");
redirectTargetDictionary.Add("controller", "Error");
redirectTargetDictionary.Add("timeout", "true");
filterContext.Result = new RedirectToRouteResult(redirectTargetDictionary);
return;
}
}
else { //continue with action as usual
base.OnActionExecuting(filterContext);
}
}
}
The problem is that every time I run the application, the SessionExpired action is fired (it finds the ASP.NET_SessionId string in the cookie when I request the application url for the first time), then when I load another url the application works OK. How to fix that?
I am using cors and asp.net membership to manage security for an API. However in some cases, the server may need to speak to our api, on behalf of the client. As in UI mvc project code behind > API.
Because the server, not authorised client would be making this call, the asp.net cookie would not be woking or picked up.
I have overloaded AuthorizeCore in order to check to see if there is a token:
if(httpContext.Request.Headers["x-access-token"] != null)
{
// this authorization is from token, rather than cookie
var accessToken = httpContext.Request.Headers["x-access-token"];
var security = new Security();
var decrypted = JsonConvert.DeserializeObject<TokenModel>(security.Decrypt(accessToken));
var clientip = GetClientIp(httpContext.Request);
if(httpContext.Request.Headers["x-client-ip"] == null)
{
return false;
}
if (httpContext.Request.Headers["x-client-ip"] != decrypted.Ip)
{
return false;
}
if (!IsSecretValid(decrypted))
{
return false;
}
MembershipUser u = Membership.GetUser(decrypted.UserId);
}
What I am asking is, How do I convert the membership into a Principle, in order to then let the rest of the code for roles etc to work.
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
Is this even possible, and if so how.
sorry, found a way through deep thought:
httpContext.User = new GenericPrincipal(new GenericIdentity(u.UserName), System.Web.Security.Roles.GetRolesForUser(u.UserName));
This should then enable my controller actions to pick up userid etc if needed.
I have a code base web application that is connected to 2 databases. Depending on which login control a user uses to login, a different database is connected to the code. I am doing all of this by a cookie. This cookie is in a public class called AuthenticatedUser. The class looks like this:
public class AuthenticatedUser : System.Web.UI.Page
{
public static string ConnectionString
{
get
{
HttpCookie myCookie = HttpContext.Current.Request.Cookies["connectionString"];
return GetConnectionStringFromName(myCookie);
}
set
{
if (HttpContext.Current.Request.Cookies["connectionString"] != null)
{
ExpireCookies(HttpContext.Current);
}
var allCookies = HttpContext.Current.Request.Cookies.AllKeys;
HttpCookie cookie = new HttpCookie("connectionString");
cookie.Value = value;
cookie.Expires = DateTime.Now.AddYears(100);
HttpContext.Current.Response.Cookies.Add(cookie);
}
}
private static string GetConnectionStringFromName(HttpCookie myCookie)
{
try
{
string connectionStringName = myCookie.Value;
return ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
}
catch
{
FormsAuthentication.SignOut();
}
finally
{
HttpContext.Current.Response.Redirect("/default.aspx");
}
return "";
} private static void ExpireCookies(HttpContext current)
{
var allCookies = current.Request.Cookies.AllKeys;
foreach (var cook in allCookies.Select(c => current.Response.Cookies[c]).Where(cook => cook != null))
{
cook.Value = "";
cook.Expires = DateTime.Now.AddDays(-1);
current.Request.Cookies.Remove(cook.Name);
cook.Name = "";
}
}
}
This seems to be working on my development machine, but when I tried to deploy it, any user that was using the "remember me" option on the site was getting a null reference error because they did not use the login control to obtain the cookie.
What is the best method to get around this? I was thinking if a user was logged in but the AuthenticatedUser class could not get a Connectionstring to log out the user to force them to use the login control again. What should I do?
Try use:
try
{
FormsAuthentication.SignOut();
}
finally
{
Response.Redirect("~/Home.aspx");
}
This way is preferable, for example if in some time you will decide not- cookie auth, but URL based - the FormsAuthentication will manage it gracefully.
I have the following code which re-uses a CookieContainer which logs in on the first request, but just uses the cookie container for requests after.
After a period of time if idle the site will give a Session Timeout, I will need to perform the login again.
Q: Can I determine (with the cookie container object) if the timeout has happened or is it best to determine if it has happened from the HttpWebResponse which happens to contains text like 'session timeout'. What is the best way to do this?
private static CookieContainer _cookieContainer;
private static CookieContainer CurrentCookieContainer
{
get
{
if (_cookieContainer == null || _cookieContainer.Count == 0)
{
lock (_lock)
{
if (_cookieContainer == null || _cookieContainer.Count == 0)
{
//_cookieContainer.GetCookies(
_cookieContainer = DoLogin();
}
}
}
return _cookieContainer;
}
set
{
_cookieContainer = value;
}
}
And then this method calls out to the container:
public static string SomeMethod(SomeParams p)
{
HttpWebRequest request_thirdPartyEnquiryDetails = (HttpWebRequest)WebRequest.Create(thirdPartyEnquiryDetails);
CookieContainer cookieContainer = CurrentCookieContainer;
request_thirdPartyEnquiryDetails.CookieContainer = cookieContainer;
//... and it goes on to submit a search and return the response
}
Well, since the timeout is 30 mins, I have set the login to repeat after 25 mins.
private static DateTime? lastLoggedIn;
private static CookieContainer _cookieContainer;
private static CookieContainer CurrentCookieContainer
{
get
{
if (_cookieContainer == null || _cookieContainer.Count == 0 || !lastLoggedIn.HasValue || lastLoggedIn.Value.AddMinutes(25) < DateTime.Now)
{
lock (_lock)
{
if (_cookieContainer == null || _cookieContainer.Count == 0 || !lastLoggedIn.HasValue || lastLoggedIn.Value.AddMinutes(25) < DateTime.Now)
{
_cookieContainer = DoLogin();
lastLoggedIn = DateTime.Now;
}
}
}
return _cookieContainer;
}
set
{
_cookieContainer = value;
}
}
As an extra precaution, I check the HttpResponse for the text which returns when the page session times out (although its now expected this won't be seen). If this happens I set the lastLoggedIn date to null and run the search method again.
You can extract all cookies for a domain using the CookieContainer.GetCookies(string uri) method. Using this CookieCollection you can get the cookie you are interested in and check its Expired property to see if it has expired.
There is one thing you should note: Your session may end even if your cookie is valid. IIS may restart the app domain the web application runs in and in that case all authenticated users may loose their session data. So checking the cookie is generally not enough to ensure that you stay logged in.
I am not sure what you want to achieve, but you should notice that CookieContainer has a bug on .Add(Cookie) and .GetCookies(uri) method.
See the details and fix here:
http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html