Antiforgery token error with SSL enabled - c#

I've created default MVC 5 website application in VS 2013 and the only thing I did was enabling SSL.
Every time I'm submitting second form (first submits fine) on Firefox I get this error:
The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
Every time I'm submitting second form I get this error:
The required anti-forgery cookie "__RequestVerificationToken" is not present.
Using IE gives no errors no matter what.
I've tried to generate and paste machine keys in web.config and it didn't help
I've tried to recreate project/restart IIS/try IIS 7 instead of IIS Express and still no good.
Disabling SSL works, but I need SSL in my project.
[ValidateForgeryAttribute]'s are set before every POST action which is called from submitting form with #Html.AntiForgeryToken() set.
Update
This is example of form that causes exception on submit, but keep in mind that so does EVERY submit with #Html.AntiForgeryToken() (and same Attribute decoration on corresponding Action).
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) {
#Html.AntiForgeryToken()
<div id="socialLoginList">
<p>
#foreach (AuthenticationDescription p in loginProviders) {
<button type="submit" class="btn btn-default" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
}
</p>
</div>
}
Action code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}

Related

The anti-forgery cookie token and form field token do not match.Error After Release [duplicate]

I'm using the default login module in ASP.NET MVC 4. I did not change any code in the default application and i hosted it on a shared server.
After i logged in using default login page. i kept the browser idle for some time. Then obviously application redirected to the login page when i try to perform any controller action with [Authorize] attribute.
Then i try to login again and it gives an error when i click on login button.
The anti-forgery cookie token and form field token do not match.
LogIn action
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
I resolved the issue by explicitly adding a machine key in web.config.
Note: For security reason don't use this key. Generate one from https://support.microsoft.com/en-us/kb/2915218#AppendixA. Dont use online-one, details, http://blogs.msdn.com/b/webdev/archive/2014/05/07/asp-net-4-5-2-and-enableviewstatemac.aspx
<machineKey validationKey="971E32D270A381E2B5954ECB4762CE401D0DF1608CAC303D527FA3DB5D70FA77667B8CF3153CE1F17C3FAF7839733A77E44000B3D8229E6E58D0C954AC2E796B" decryptionKey="1D5375942DA2B2C949798F272D3026421DDBD231757CA12C794E68E9F8CECA71" validation="SHA1" decryption="AES" />
Here's a site that generates unique Machine Keys:
http://www.developerfusion.com/tools/generatemachinekey/
Another reason for having this error is if you are jumping between [Authorize] areas that are not cached by the browser (this would be done on purpose in order to block users from seeing protected content when they sign out and using the back button for example).
If that's case you can make your actions non cached, so if someone click the back button and ended up on a form with #Html.AntiForgeryToken() the token will not be cached from before.
See this post for how to add [NoCache] ActionFilterAttribute:
How to handle form submission ASP.NET MVC Back button?
make sure you put the #Html.AntiForgeryToken() in your page's form
I had this problem for a long time and assumed it was something wrong with ASP.NET.
In reality, it was the server. I was with WinHost then, and they have a 200MB memory limit. As soon as I had ~20 users on at the same time, my limit was reached. At this point, everyone was logged out and yielded these issues.
For me, this was caused by submitting a form using a button tag. Changing this to an input submit tag resolves the issue.
In My case "We found that the Site cache was enabled and due to this “anti-forgery” token value was not updating every time, after removing this cache
form is submitting."
In my case it was related to multiple cookie values set by domain site and subdomain site.
main.com set __RequestVerificationToken = 1
sub.main.com set __RequestVerificationToken = 2
but when request to sub.main.com was sent it used __RequestVerificationToken = 1 value from main.com

MVC - anti-forgery token error

I've been brought onto my first MVC and C# project so I appreciate any guidance.
I've created a new feature that checks to see if user has had security training when they log in. If they haven't, the user is directed to a training page where they simply agree/disagree to the rules. If the user agrees, login is completed. If user disagrees, he/she is logged off.
The issue that I have is that when I select the Agree/Disagree button in the training view, I get the following
It should route me to the homepage or logout the user.
Controller
public ActionResult UserSecurityTraining(int ID, string returnUrl)
{
// check if user already has taken training (e.g., is UserInfoID in UserSecurityTrainings table)
var accountUser = db.UserSecurityTraining.Where(x => x.UserInfoID == ID).Count();
// If user ID is not in UserSecurityTraining table...
if (accountUser == 0)
{
// prompt security training for user
return View("UserSecurityTraining");
}
// If user in UserSecurityTraining table...
if (accountUser > 0)
{
return RedirectToLocal(returnUrl);
}
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UserSecurityTrainingConfirm(FormCollection form, UserSecurityTraining model)
{
if (ModelState.IsValid)
{
if (form["accept"] != null)
{
try
{
// if success button selected
//UserSecurityTraining user = db.UserSecurityTraining.Find(); //Create model object
//var user = new UserSecurityTraining { ID = 1, UserInfoID = 1, CreatedDt = 1 };
logger.Info("User has successfully completed training" + model.UserInfoID);
model.CreatedDt = DateTime.Now;
db.SaveChanges();
//return RedirectToAction("ChangePassword", "Manage");
}
catch (Exception e)
{
throw e;
}
return View("SecurityTrainingSuccess");
}
if(form["reject"] != null)
{
return RedirectToAction("Logoff", "Account");
}
}
return View("UserSecurityTraining");
}
View
#model ECHO.Models.UserSecurityTraining
#{
ViewBag.Title = "Security Training";
Layout = "~/Views/Shared/_LayoutNoSidebar.cshtml";
}
<!--<script src="~/Scripts/RequestAccess.js"></script>-->
<div class="container body-content">
<h2>#ViewBag.Title</h2>
<div class="row">
<div class="col-md-8">
#using (Html.BeginForm("UserSecurityTrainingConfirm", "Account", FormMethod.Post, new { role = "form" }))
{
<fieldset>
#Html.AntiForgeryToken()
Please view the following security training slides:<br><br>
[INSERT LINK TO SLIDES]<br><br>
Do you attest that you viewed, understood, and promise to follow the guidelines outlined in the security training?<br><br>
<input type="submit" id="accept" class="btn btn-default" value="Accept" />
<input type="submit" id="reject" class="btn btn-default" value="Reject" />
</fieldset>
}
</div><!--end col-md-8-->
</div><!--end row-->
</div><!-- end container -->
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I don't think you've provided enough of your code to properly diagnose this particular error. In general, this anti-forgery exception is due to a change in authentication status. When you call #Html.AntiForgeryToken() on a page, a cookie is set as well in the response with the token. Importantly, if the user is authenticated, then the user's identity is used to compose that token. Then, if that user's authentication status changes between when the cookie is set and when the form is posted to an action that validates that token, the token will no longer match. This can either be the user being authenticated after the cookie set or being logged out after the cookie is set. In other words, if the user is anonymous when the page loads, but becomes logged in before submitting the form, then it will still fail.
Again, I'm not seeing any code here that would obviously give rise to that situation, but we also don't have the full picture in terms of how the user is being logged in an taken to this view in the first place.
That said, there are some very clear errors that may or may not be causing this particular issue, but definitely will cause an issue at some point. First, your buttons do not have name attributes. Based on your action code, it appears as if you believe the id attribute will be what appears in your FormCollection, but that is not the case. You need to add name="accept" and name="reject", respectively, to the buttons for your current code to function.
Second, on the user successfully accepting, you should redirect to an action that loads the SecurityTrainingSuccess view, rather than return that view directly. This part of the PRG (Post-Redirect-Get) pattern and ensures that the submit is not replayed. Any and all post actions should redirect on success.
Third, at least out of the box, LogOff is going to be a post action, which means you can't redirect to it. Redirects are always via GET. You can technically make LogOff respond to GET as well as or instead of POST, but that's an anti-pattern. Atomic actions should always be handled by POST (or a more appropriate verb like PUT, DELETE, etc.), but never GET.
Finally, though minor, the use of FormCollection, in general, is discouraged. For a simple form like this, you can literally just bind your post as params:
public ActionResult UserSecurityTrainingConfirm(string accept, string reject, ...)
However, then it'd probably be more logical and foolproof to introduce a single boolean like:
public ActionResult UserSecurityTrainingConfirm(bool accepted, ...)
Then, your buttons could simply be:
<button type="submit" name="accepted" value="true" class="btn btn-default">Accept</button>
<button type="submit" name="accepted" value="false" class="btn btn-default">Reject</button>
This essentially makes them like radios. The one that is clicked submits its value, so the accepted param, then, will be true or false accordingly. Also, notice that I switched you to true button elements. The use of input for buttons is a bad practice, especially when you actually need it to submit a value, since the value and the display are inherently tied together. With a button element, you can post whatever you want and still have it labeled with whatever text you want, independently.

How to resolve: The provided anti-forgery token was meant for a different claims-based user than the current user

I am getting this error:
The provided anti-forgery token was meant for a different claims-based user than the current user.
and I am not sure how to correct this..
I have a MVC5 site and in this site I have a login page.
This is the scenario that it occurs on.
User AAA logs in. (No issues)
I attempt to access a view where the user does not have access.
I have the class decorated with an Authorize(Roles="aa")
The view then logs the user off and puts them back to the login page.
User AAA logs in. (This time I get the error mentioned above)
To note:
I am using customErrors and this is where I see the error message.
When I log the user out I am running this method:
[HttpGet]
public void SignOut()
{
IAuthenticationManager authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.SignOut(MyAuthentication.ApplicationCookie);
}
Could I possibly be missing something on the SignOut?
UPDATE:
This only occurs because of step #2 listed above.
If I log in, then log out (calling same code) then log back in, then I do not have this issue.
I think you've neglected to post some relevant code. The Signout action you have returns void. If you were to access this action directly in the browser, then the user would get a blank page after being signed out with no way to progress forward. As a result, I can only assume you are either calling it via AJAX or calling as a method from another action.
The way anti-forgery works in MVC is that a cookie is set on the user's machine containing a unique generated token. If the user is logged in, their username is used to compose that token. In order for a new cookie, without a username to be set, the user must be logged out and a new request must occur to set the new cookie. If you merely log the user out without doing a redirect or something, the new user-less cookie will not have been set yet. Then, when the user posts, the old user-based cookie is sent back while MVC is looking for the new user-less cookie, and boom: there's your exception.
Like I said, you haven't posted enough code to determine exactly why or where this is occurring, but simply, make sure there is a new request made after logging the user out, so the new cookie can be set.
I was able to reproduce by clicking on the login button more than once before the next View loads. I disabled the Login button after the first click to prevent the error.
<button type="submit" onclick="this.disabled=true;this.form.submit();"/>
Disable the identity check the anti-forgery validation performs. Add the following to your Application_Start method:
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.
try:
public ActionResult Login(string modelState = null)
{
if (modelState != null)
ModelState.AddModelError("", modelState);
return View();
}
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model)
{
AuthenticationManager.SignOut();
return RedirectToAction("Login", "Controller", new { modelState = "MSG_USER_NOT_CONFIRMED" });
}
I haved similar problem. I found this text "#Html.AntiForgeryToken() " in my project in 2 place. And one plase will was in "view file" Views - test.cshtml.
#using (Html.BeginForm())
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="form-group">
#if (#Model.interviewed)
...
I deleted this code line ("#Html.AntiForgeryToken() ") and working fine.
PS: But I am not delete this code in file _LoginPartial.cshtml.
Good luck!

Rewriting Url in ASP.Net MVC

I am struggling over this issue since yesterday.I am working on a web application which includes email service.Email includes 'link' to a certain page of that application.
Now:I have 2 scenarios:
1) If the user is logged in(in the application) already and he hit
the url he got in his email,the link will open perfectly.
2) If the user is not logged in(in the application) then the url
will not open and will redirect itself to the login page with the
functionality added in the BaseController.
*
Now what I want is when the user logs in after hitting the url and on
successfully login the user gets redirect to the link provided in the
Email.
*
for eg: If the user gets an email to the detail page of an employee,So on successfully login the user gets redirect to the Detail page of the employee.
Something like appending the redirecturl to the login page.
I think rewriting url is what I should be doing.
But I dont know how can I use that in this case.Help me out.
The default project template that comes with ASP.NET MVC 5 behaves exactly as you describe.
If you want to redirect to a custom login URL, reconfigure the LoginPath property of the CookieAuthenticationOptions object
LoginPath = new PathString("/Account/Login")
In the default template this is done in the Startup.Auth.cs class.
NOTE: If you are using an old version of ASP.NET MVC, the default project template behaved in the same way. But previously this was implemented using Forms Authentication, so in order to redirect to a custom login URL you would then have to set the loginUrl attribute of the <forms> tag in the Web.config file
By default if a user tries to access the authorized page when he is not authorized the automatically gets redirected to the log in page or the page which is configured in web.config file for the element. And you can see the query string returnUrl having the url that was tried to access initially get appended to the log in url.
To access the return url, include a new parameter as returnUrl and maintain the return url in a hidden field by model data to access on post back for redirection.
If the user is authenticated then on post back then redirect the user to the specified page what he intended to go for.
I don't remember exactly but few month ago I implemented similar functionality and i had to save returnUrl explicitly (due to MVC bug or something) - Refer this link
AccountController.cs - Snapshot
[HttpGet]
[AllowAnonymous]
public ActionResult Login(string returnUrl, string userName)
{
// You login method logic....
// Add this line to save the returnUrl value
ViewBag.ReturnUrl = returnUrl;
}
Login.cshtml - Snapshot
#using (Html.BeginForm("Login", "Account", FormMethod.Post ,new {ReturnUrl = ViewBag.ReturnUrl}))
{
<input type="hidden" name="ReturnUrl" value="#Request.QueryString["ReturnUrl"]" />
// .....
}
See if this helps in your case.

MVC AntiForgery Token error

I am wondering how I should be handeling the following error/issue. I have a form that is getting submitted and on that form I am using AntiForgery token. The purpose of the form is to login to the site.
In the view I have:
<%: Html.AntiForgeryToken()%>
The controller reads:
[HttpPost]
[HandleError(ExceptionType = typeof(HttpAntiForgeryException),Master = "MasterLogin", View = "Login")]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginPresentation model, string returnUrl)
{
//do stuff
}
It works really well for the most part. Expect for the following case.
I login to the site
Logout of the site
Clear my cache
Attempt to authenticate
When I try to login I get the following error:
The required anti-forgery cookie "__RequestVerificationToken_L1NTSS5NZW1iZXJzaGlwLlBvcnRhbA2" is not present.
How should I be dealing with this?
Just make sure that every request that is sent towards an action decorated with the ValidateAntiForgeryToken attribute is made via HTTP POST and it comes from a form that has a hidden input containing the required token.
It can be generated using Html.AntiForgeryToken() and it looks like this:
<input name="__RequestVerificationToken" type="hidden" value="some value" />
The token associated with the form is also stored as a cookie on the client machine, so when you submit the form, the ValidateAntiForgeryToken filter checks the following:
The incoming request has a cookie called __RequestVerificationToken
The incoming request has a Request.Form entry called __RequestVerificationToken
These cookie and Request.Form values match
read more here.

Categories