How does AntiForgeryToken, specifically, 'match up' with a cookie? - asp.net-mvc-4

We have a web page, and it has a form on it. There is an antiforgerytoken added to this MVC page's form via the helper:
#Html.AntiForgeryToken()
We realised today that we have the page cached, which we thought would be a massive issue, but multiple machines may submit the same form, even though they share the same verification token in the page's source!?
This is unexpected as far as I'm aware, I thought the idea was that the same verification token can be found in the cookie? I'm obviously misunderstanding the mechanism behind the token (both on the page and the amendment of a user's cookie).
Can somebody explain to me how this page still works? More specifically, how the server validates the form's post request.
I thought it was as simple as the server checking that the token string was identical to a token string found in the cookie.
NB: Caching is turned off for now fwiw, we're not 100% happy with caching a page with tokens on it now that we're a bit more clued up on it.

We realised today that we have the page cached, which we thought would be a massive issue, but multiple machines may submit the same form, even though they share the same verification token in the page's source!?
Yes, caching is a problem when it comes to anti-forgery tokens. You have two choices:
Don't cache the form.
Use the VaryByCustom property of OutputCache to vary by the token itself.
I don't have code to hand with me, so I'll show you an example which is taken from this article:
In order to avoid this issue you can use the VaryByCustom property on the OutputCache attribute:
[OutputCache(
Location = OutputCacheLocation.ServerAndClient,
Duration = 600,
VaryByParam = "none",
VaryByCustom = "RequestVerificationTokenCookie")]
public ActionResult Index()
{
return new View();
}
And then program the rule on the global.asax‘s GetVaryByCustomString method:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom.Equals("RequestVerificationTokenCookie", StringComparison.OrdinalIgnoreCase))
{
string verificationTokenCookieName =
context.Request.Cookies
.Cast<string>()
.FirstOrDefault(cn => cn.StartsWith("__requestverificationtoken", StringComparison.InvariantCultureIgnoreCase));
if (!string.IsNullOrEmpty(verificationTokenCookieName))
{
return context.Request.Cookies[verificationTokenCookieName].Value;
}
}
return base.GetVaryByCustomString(context, custom);
}
Edit per comments
The reason it works is because it's only comparing the value of the cookie to the value of the generated hidden field on the form. There isn't a list of tokens maintained on the server, ready to be validated, if you thought it might work that way. That means, as far as the client is concerned, despite the generation of the form being cached on the server, the client is still receiving a 'new' form and, consequently, a cookie to go along with that, so the comparison won't fail.

Related

Session lost after redirect SAML: may be different webapps?

I am fairly new to webapps programming, so I thought of asking here.
I am implementing the SAML2 protocol in an open source app (namely OFBiz) but I am encountering a problem related to session loss after the protocol made its course.
I am following these steps to implement the protocol. Suppose ofbizwebsite.com is the URL of the site.
Installed a custom plugin named SAMLIntegration which exposes the ACS page and the logic for login. To my understanding, a plugin (gradle) is like an indipendent java project, which translates to a new set of resources for the application (the plugin enables, for example, to visit ofbizwebsite.com/SAMLIntegration and setup some resources).
Exposed the ACS page to ofbizwebsite.com/SAMLIntegration/control/acs, as well as metadata ofbizwebsite.com/SAMLIntegration/control/metadata.jsp
Created the logic for login. Basically, an entity called UserLogin is saved in the session and recovered by a "checker" to understand if an user is logged in. Suppose that this checker is a HTTP WebEvent handler which can be called by any resource requiring authentication.
Now, the problem. If redirect the user to a resource on SAMLIntegration (for example ofbizwebsite.com/SAMLIntegration/control/aview or any ofbizwebsite.com/SAMLIntegration/control/* by calling response.sendRedirect("aview")) check works and login is preserved. Visiting any resource (for example ofbizwebsite.com/aplugin/control/anotherview) by navigating the application does not preserve the session.
OFBiz use internally a mechanism for preserving the userLogin between webapps, by creating an HashMap between and UUID and a UserLogin object. The UUID is passed between two different resources, appending this key to each path (so ofbizwebsite.com/aplugin/control/anotherview?externalKey=THEEFFECTIVEUUID)
To my understanding, changing from ofbizwebsite.com/SAMLIntegration/control/* to ofbizwebsite.com/aplugin/control/* determine a session loss. So, my idea was to replace the UUID mechanism with SAML2. However, I do not know how to solve this problem.
In particular, I would like to execute a SAML request each time the checker function is executed. If I can't find the user in the session, a SAML request is fired. However, my problem is HOW to manage the response. Normally, I would redirect it to the acs ofbizwebsite.com/SAMLIntegration/control/acs. Doing so, however, does not allow me to handle the response in the checker function, as the control is passed to another servlet by an external request (the SAML response fired by the IdP). Should I provide a different acs for each different path? (so one for SAMLIntegration and one for aplugin?) And, even if this was the case, how can I return the control to the checker function which has invoked the SAML request?
Here you go for installing the Shibboleth HTTPD module: https://pad.nereide.fr/SAMLWithShibboleth
You also need this method somewhere in OFBiz (I recommend LoginWorker.java, but you can put it where you want). It allows to use the externalAuthId of the userLogin for authentication, with the uid returned by the sso:
public static String checkShibbolethRequestRemoteUserLogin(HttpServletRequest request, HttpServletResponse response) {
LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
Delegator delegator = dispatcher.getDelegator();
// make sure the user isn't already logged in
if (!LoginWorker.isUserLoggedIn(request)) {
String remoteUserId = (String) request.getAttribute("uid"); // This is the one which works, uid at Idp, remoteUserId here
if (UtilValidate.isNotEmpty(remoteUserId)) {
//we resolve if the user exist with externalAuthId
String userLoginId = null;
GenericValue userLogin;
try {
List<GenericValue> userLogins = delegator.findList("UserLogin",
EntityCondition.makeConditionMap("externalAuthId", remoteUserId, "enabled", "Y"),
null, null, null, true);
userLogin = userLogins.size() == 1 ? userLogins.get(0) : null;
} catch (GenericEntityException e) {
Debug.logError(e, module);
return "error";
}
if (userLogin != null) {
userLoginId = userLogin.getString("userLoginId");
}
//now try to log the user found
return LoginWorker.loginUserWithUserLoginId(request, response, userLoginId);
}
}
return "success";
}
You also need to have this method as an OFBiz preprocessor in the webapp controllers. I suggest to have a look at common-controller.xml.
Finally you need the configs that redirect to the SSO page if no session. That should do the job, at least it works for them...
Finally I recommend https://www.varonis.com/blog/what-is-saml in case of need.

Blazor WASM - OpenIdConnect - Disable token validation to identity provider on every page refresh

We are creating a Blazor WASM application for usage on unstable and possibly slow connections. We have successfully implemented authentication with OpenIdConnect.
We noticed that on every refresh (F5) of the page, the token is being validated against the Identity Provider again:
We think this is normal/desired behaviour, but is there any way around this?
We know this is a tiny amount of data, but it would be optimal to not have this every time.
The websites are for 'internal' usage only (through a VPN).
Thank you
I have personally run into this issue as well. For us, it was even worse since the IdP would take quite some time since the authorization endpoint would ignore the prompt=none parameter and try to challenge the user every time Blazor WASM Authentication tried to refresh its authentication state. This forced me to do some digging so hopefully, my findings are useful to you.
The OIDC in Blazor WASM makes use of their RemoteAuthenticationService class which implements the AuthenticationStateProvider to provide an authentication state to Blazor WASM on top of the Access Token.
I think this is the key problem here. That they are separating the AuthState and AccessToken which (at least for me) was unintuitive since in the past I would determine whether a user is "logged in", purely based on if they have a valid access token or not.
So the fact that you already have an "AccessToken" is irrelevant to the AuthState which begs the question: How do they determine your AuthState?
Lets checkout this key function in the RemoteAuthenticationService:
...
public override async Task<AuthenticationState> GetAuthenticationStateAsync() => new AuthenticationState(await GetUser(useCache: true));
...
private async Task<ClaimsPrincipal> GetUser(bool useCache = false)
{
var now = DateTimeOffset.Now;
if (useCache && now < _userLastCheck + _userCacheRefreshInterval)
{
return _cachedUser;
}
_cachedUser = await GetAuthenticatedUser();
_userLastCheck = now;
return _cachedUser;
}
In the above code snippet you can see that the AuthState is determined by this GetUser function which first checks some cache for the user which is currently hardcoded to expire every 60 seconds. This means that if you check the user's AuthState, then every 60 seconds it would have to query the IdP to determine the AuthState. This is how it does that:
Uses JSInterop to call trySilentSignIn on the oidc-client typescript library.
SilentSignIn opens a hidden iframe to the IdP authorization endpoint to see if you are in fact signed in at the IdP. If successful then it reports the signed-in user to the AuthState provider.
The problem here is that this could happen every time you refresh the page or even every 60 seconds whenever you query the current AuthState where the user cache is expired. There is no persistence of the access token or the AuthState in any way.
Ok so then how do I fix this?
The only way I can think of is to implement your own RemoteAuthenticationService with some slight modifications from the one in the Authentication Library.
Specifically to
Potentially persist the access token.
Reimplement the getUser call to check the validity/presence of the persisted access token to get the user rather than using the silentSignin function on the oidc-client library.

How HTTP caching works in asp mvc 4

I have a controller which returns SVG images.As I wanted to have good performances, I decide to use Caching.
From what I read on the web,once you set the last modified date with HttpContext.Response.Cache.SetLastModified(date)
you can request it from the browser using HttpContext.Request.Headers.Get("If-Modified-Since"). Compare the two dates. If they are equal it means that the image has not been modified, therefore you can return HttpStatusCodeResult(304, "Not Modified").
But something weird is happening, here is my code:
[OutputCache(Duration = 60, Location = OutputCacheLocation.Any, VaryByParam = "id")]
public ActionResult GetSVGResources(string id)
{
DateTime lastModifiedDate = Assembly.GetAssembly(typeof(Resources)).GetLinkerTime();
string rawIfModifiedSince = HttpContext.Request.Headers.Get("If-Modified-Since");
if (string.IsNullOrEmpty(rawIfModifiedSince))
{
// Set Last Modified time
HttpContext.Response.Cache.SetLastModified(lastModifiedDate);
}
else
{
DateTime ifModifiedSince = DateTime.Parse(rawIfModifiedSince);
if (DateTime.Compare(lastModifiedDate, ifModifiedSince) == 0)
{
// The requested file has not changed
return new HttpStatusCodeResult(304, "Not Modified");
}
}
if (!id.Equals("null"))
return new FileContentResult(Resources.getsvg(id), "image/svg+xml");
else
return null;
}
What is happening is the function
HttpContext.Response.Cache.SetLastModified(lastModifiedDate); does not set the "If-Modified-Since" return from the browser, In fact the the function HttpContext.Request.Headers.Get("If-Modified-Since") retuns exactly the time when the image is returned from the previous call return new FileContentResult(Resources.getsvg(id), "image/svg+xml");.
So my question is,
1 - What does the function HttpContext.Response.Cache.SetLastModified(lastModifiedDate) set exactly ?
2 - How can I (the server) set the "If-Modified-Since" return by the browser ?
It seems like you're muddling a bunch of related but nonetheless completely different concepts here.
OutputCache is a memory-based cache on the server. Caching something there means that while it still exists in memory and is not yet stale, the server can forgo processing the action and just returned the already rendered response from earlier. The client is not involved at all.
HTTP cache is an interaction between the server and the client. The server sends a Last-Modified response header, indicating to the client when the resource was last updated. The client sends a If-Modified-Since request header, to indicate to the server that its not necessary to send the resource as part of the response if it hasn't been modified. All this does is save a bit on bandwidth. The request is still made and a response is still received, but the actual data of the resource (like your SVG) doesn't have to be transmitted down the pipe.
Then, there's basic browser-based caching that works in concert with HTTP cache, but can function without it just as well. The browser simply saves a copy of every resource it downloads. If it still has that copy, it doesn't bother making a request to the server to fetch it again. In this scenario, a request may not even be made. However, the browser may also send a request with that If-Modified-Since header to see if the file it has is still "fresh". Then, if it doesn't get the file again from the server, it just uses its saved copy.
Either way, it's all on the client. A client could be configured to never cache, in which case it will always request resources, whether or not they've been modified, or it may be configured to always use a cache and never even bother to check it the resource has been updated or not.
There's also things like proxies that complicate things further still, as the proxy acts as the client and may choose to cache or not cache at will, before the web browser or other client of the end-user even gets a say in the matter.
What all that boils down to is that you can't set If-Modified-Since on the server and you can't control whether or not the client sends it in the request. When it comes to forms of caching that involve a client, you're at the whims of the client.

.NET Core alternative to ThreadPool.QueueUserWorkItem

I'm working on implementing the ForgotPassword functionality ie in the AccountController using ASP.NET Identity as in the standard VS 2015 project template.
The problem I'm trying to solve is that when the password reset email is sent, there is a noticeable delay in the page response. If the password recovery attempt does not find an existing account then no email is sent so there is a faster response. So I think this noticeable delay can be used for account enumeration, that is, a hacker could determine that an account exists based on the response time of the forgot password page.
So I want to eliminate this difference in page response time so that there is no way to detect if an account was found.
In the past I've queued potentially slow tasks like sending an email onto a background thread using code like this:
ThreadPool.QueueUserWorkItem(new WaitCallback(AccountNotification.SendPasswordResetLink),
notificationInfo);
But ThreadPool.QueueUserWorkItem does not exist in .NET Core, so I'm in need of some alternative.
I suppose one idea is to introduce an artificial delay in the case where no account is found with Thread.Sleep, but I'd rather find a way to send the email without blocking the UI.
UPDATE: To clarify the problem I'm posting the actual code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await userManager.FindByNameAsync(model.Email);
if (user == null || !(await userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
var code = await userManager.GeneratePasswordResetTokenAsync(user);
var resetUrl = Url.Action("ResetPassword", "Account",
new { userId = user.Id, code = code },
protocol: HttpContext.Request.Scheme);
//there is a noticeable delay in the UI here because we are awaiting
await emailSender.SendPasswordResetEmailAsync(
userManager.Site,
model.Email,
"Reset Password",
resetUrl);
return View("ForgotPasswordConfirmation");
}
// If we got this far, something failed, redisplay form
return View(model);
}
Is there a good way to handle this using other built in framework functionality?
Just don't await the task. That's then mostly-equivalent to running all of that code on the thread-pool to start with, assuming it doesn't internally await anything without calling ConfigureAwait(false). (You'll want to check that, if it's your code.)
You might want to add the task to some set of tasks which should be awaited before the server shuts down, assuming there's some appropriate notion of "requested shutdown" in ASP.NET. That's worth looking into, and would stop the notification from being lost due to unfortunate timing of the server being shut down immediately after sending the response but before sending the notification. It wouldn't help in the case where there are problems in sending the notification though, e.g. your mail server is down. At that point, the user has been told that the email is on its way, before you can really guarantee that... just something to think about.

CakePHP Authentication on REST API

So I'm creating a REST API for a web app I'm developing, and I know the basic ways for authentication are either sending the credentials on each request or sending a token.
Since I have never used token before, I think I may send the credentials for each request. The point is I can't find any examples on how to handle this in the controller. Would it be something like this?
public function api_index() {
if(!$this->Auth->login()) return;
$this->set(array(
'models' => $this->Model->find('all'),
'_serialize' => array('models')
));
}
I don't really think this is the way AuthComponent::login() works, can I get some directions here please?
Alright, first a clarification about how AuthComponent::login works. In Cake 2.x that method does not do any authentication, but rather creates the Auth.User array in your session. You need to implement the actual authentication yourself (the User model is a natural place to do this). A basic authentication method might look like this:
App::uses('AuthComponent', 'Controller/Component');
public function authenticate($data) {
$user = $this->find('first', array(
'conditions' => array('User.login' => $data['login']),
));
if($user['User']['password'] !== AuthComponent::password($data['password']) {
return false;
}
unset($user['User']['password']); // don't forget this part
return $user;
// the reason I return the user is so I can pass it to Authcomponent::login if desired
}
Now you can use this from any controller as long as the User model is loaded. You may be aware that you can load it by calling Controller::loadModel('User').
If you want to authenticate every request, then you should then put in the beforeFilter method of AppController:
public function beforeFilter() {
$this->loadModel('User');
if(!$this->User->authenticate($this->request->data)) {
throw new UnauthorizedException(__('You don\'t belong here.'));
}
}
All of the above assumes that you pass POST values for login and password every time. I think token authentication is definitely the better way to go, but for getting up and running this should work. Some downsides include sending password in cleartext (unless you require ssl) every request and the probably high cpu usage of the hashing algorithm each time. Nevertheless, I hope this gives you a better idea of how to do authentication with cakephp.
Let me know if something needs clarifying.
Update:
Since posting this, I found out that you can actually use AuthComponent::login with no parameters, but I am not a fan of doing so. From the CakePHP documentation:
In 2.x $this->Auth->login($this->request->data) will log the user in with
whatever data is posted, whereas in 1.3 $this->Auth->login($this->data)
would try to identify the user first and only log in when successful.
AuthComponent::login() creates a session variable that stores the user data, so say you had data that was something like.
$data = array('User' => array('id' => 1, 'username' => 'johndoe'));
Then you would use
$this->Auth->login($data);
And access the data with
$this->Auth->user('User');
To get the user id
$this->Auth->user('User.id');
In your AppControllers beforefilter put $this->Auth->deny(); that will deny all actions to someone who is not logged in. Then in each controllers before filter you want to $this->Auth->allow(array('view')); 'view' being the name of an action you want to be public.
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
Cakephp 2.X, After lots of research about this on internet I did not find any satisfactory answer So I found a way myself to do this. May be this answer will help some folks in future. This answer is only applicable for REST API's in cake php.
Add following line in your logic action of REST API before checking for the $this->Auth->login().
$this->request->data['User'] = $this->request->data ;
if($this->Auth->login()){
echo "Hurray You are logged In from REST API.";
}
else
{
throw new UnauthorizedException(__('You don\'t belong here.'));
}
Desciption : As #threeve said in one of the answers that $this->Auth->login() does not do any authentication itself. but rather creates the Auth.User array in your session. For Authentication we require our $this->request->data to be inside User array since User is the model which will check the Credentials in Database. Therefore we have to pass the data to Auth as it is required when not using REST API's. Rest of the things will be handled by Cake and Auth itself.
Any enhancements or suggestions on this answer are most welcome.