I am having a very weird CSRF protection problem in CodeIgniter. I have made sure that I use form_open to start my form, csrf_protection is set to true in the config file, and I have also made sure that the hidden csrf name and value fields match the csrf cookie as seen here: http://d.pr/3cfB.
What happens is that when I submit the form, I get "An Error Was Encountered. The action you have requested is not allowed." error and am not sure why. The form works fine when I turn the csrf_protection off.
What's even weirder is that I use tank_auth library for my authentication and it also uses form_open for the login form. I did check to make sure that there is a hidden csrf field in the login form when csrf_protection is on and I was able to submit the form and log in with no problem.
Thoughts on what I can do to debug this problem?
To begin with, the session class is expecting a token named 'csrf_token_name', not one named 'csrf_salemarked_token$...'.
This blog post covers AJAX with CSRF Protection in Codeigniter 2.0.
Tank_auth is getting the token from the hidden input form field, rather than the cookie. Your AJAX requests need to get the token from the hidden field if available, or the cookie if there is no form.
I found the problem. In one of my custom libraries I have parent::_sanitize_globals() which apparently was what's causing the error. I read somewhere that if I have xss filtering turned on, I don't need to do sanitize global.
Related
I'm trying to better understand the mechanism for how Spring CSRF protection works. Suppose I have a site https://example.com/ where people can vote on candidates. Users can also exchange messages. I also have a user logged in, and another user that sends her a message saying to click on the link https://example.com/vote/candiate/30.
If a user clicks on this link, won't the browser send both the CSRF token and the session ID for the logged in user, thereby bypassing the CSRF protection check?
The reason a link is usually not a problem regarding CSRF is that CSRF is only an issue when the request changes something. A link (a GET request) should not change anything. If it does, like in your example it adds a vote to the candidate I suppose, any link from an external origin (a different website) would also be able to exploit "normal" CSRF by just linking to that url.
The problem in the example is not that CSRF protection is inadequate in Spring, the problem is that voting in this case is a GET request, and GETs are not usually protected against CSRF by design. The solution is to change the vote request to a POST, which would then be protected against CSRF (and which would also be more RESTful btw).
Main idea :
When request is submitted, the server received special cookie and waits for defined value in this cookie. If this value will be differet , the request should fail.
So, if service returns form for moving money between accounts, this form includes parameter, that expected to receive when form is submitted, and if data would be sent without this parameter, request wouldn't be proccessed
I have a login form submitted with Ajax. In one specific case, after the user logs in, I need to log them out with Auth::logout() and display an additional modal box. All of this happens with no page reload.
When the login modal is opened and submitted again, I get a Token mismatch error. The reason why this happens is because the logout uses Session::flush(). After this the _token Session variable is refreshed, while the _token input in the login form stays the same (because of the mentioned lack of page reload).
How can I refresh the CSRF _token in the login form, so it matches the one refreshed in the Session in a secure way?
When your login is submitted via ajax, your server is presumably sending back some kind of response to let the browser know the login was successful. You should send back the new CSRF token with this response, so that you can update the form client-side (with javascript).
To provide any more detail (how to update form fields, for example) we would need to see more of your code.
I'm using Symfony2 and protecting my forms with a CSRF token.
I have a comments system based on Ajax calls. If a user wants to edit his comment, here's what's happening:
A user hits the edit button.
A "fresh" comment edit form is loaded via ajax.
The user edit and submit the form via ajax.
The edited comment is sent back in response.
Is loading the "fresh" edit form via ajax a security risk?
If the form were already in the loaded page and couldn't be requested via ajax, an attacker could not guess the CSRF Token, but since he can request the form he can get his hands on the Token..
Couldn't he..?
Maybe an example will make it clearer:
Dave is an innocent registered user in my site (www.acme.com).
Dave logged in my site and then visited www.evil.com. He doesn't know that, but when he visited evil.com a script was executed.
The script sent an ajax request to www.acme.com/comments/123/edit and got the edit form in response.
It then filled in that form with it's malicious content and submitted that form (again, with ajax).
Will evil's evil plan work?
As far as i understand, there is no risk if your form contains CSRF token field. Default Symfony2 CSRF token depends on session which is not availiable for the attacker (and also on intention). So when the attacker requests the form there is attacker's (not user's) session id used.
I have a page on domain A which includes a javascript from from domain B. The script loads a form from domain A with Ajax and posts it back to A.
The form got rejected by Yesod because of missing session variable which resides in a cookie and isn't transmitted on Ajax request because of that.
Can Yesod's session mechanism be made work in such a situation?
I was given an answer by Michael Shoyman, the author of Yesod. The easiest way in my case is to disable CSRF protection for that particular form. There is an api function for that.
http://hackage.haskell.org/packages/archive/yesod-form/1.1.4.1/doc/html/Yesod-Form-Functions.html#v:runFormPostNoToken
We have a website that uses MVC3 and a custom authentication method that does not rely on forms authentication at all -- at least from what I can tell. In web.config we set
<authentication mode="None"></authentication>
and we never use/set HttpContext.User anywhere in code. The problem is when using #Html.AntiForgeryToken() in some cases the user gets this error message:
A required anti-forgery token was not supplied or was invalid
We centralize all anti-forgery checks in OnAuthorization with this code:
if (String.Compare(filterContext.HttpContext.Request.HttpMethod, "post", true) == 0)
{
var forgery = new ValidateAntiForgeryTokenAttribute();
forgery.OnAuthorization(filterContext);
}
That is where the exception occurs. We have defined a machineKey in web.config to prevent new keys being generated when the application pool recycles. This did not fix the problem.
Next we thought that maybe the client's browser is not sending cookies. We started logging cookies and noticed that in some cases the RequestVerificationToken_Lw cookie is sent, but in others is not -- even though other cookies, like the ones made by Google Analytics, are sent along just fine. Could it be something in the browser is stripping out some cookies and leaving others in?
It seems like the anti-forgery token depends on forms authentication. Is this the case? Any way to keep using the AntiForgeryToken when not using forms authentication in a reliable way. Keep in mind that the method I described above works for more than 90% of cases, but we can't pinpoint why it doesn't work for some people.
Thoughts?
Thanks!
Do some users have this issue all the time? Or just some of the time? Also, does it work for some of the methods ALL the time or is it inconsistent for the same action method? Do you have any ajax calls? The default anti-forgery token implementation does not handle AJAX calls. But you can write some custom code to get it to work
Are you adding the antiforgery token inside of the form? The antiforgery token is stored on the client via a hidden HTML element so and not as a cookie. The other question would be what browser version are they using? Are can the upgrade to the latest?
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()...