We use cookies to improve your experience. No personal information is gathered and we don't serve ads. Cookies Policy.

ExpressionEngine Logo ExpressionEngine
Features Pricing Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University
Log In or Sign Up
Log In Sign Up
ExpressionEngine Logo
Features Pro new Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University Blog
  • Home
  • Forums

XID required for POST requests to action URLs?

Developer Preview

Brad Parscale's avatar
Brad Parscale
196 posts
12 years ago
Brad Parscale's avatar Brad Parscale

Assuming Secure Forms is enabled:

In all previous versions of ExpressionEngine doing a POST request to an action URL - eg. http://domain.com/index.php?ACT=XX - did not require a XID field in the POST.

Doing the same now in EE 2.7 returns an error: The action you have requested is invalid.

When i add the XID field the AJAX request works fine. (using window.EE.XID) However, adding the XID field will invalidate the XID and sending a subsequent AJAX request fails again.

If you where working on a form this will also make the form useless, since submitting the form will redirect you to the CP homepage.

Are we supposed to refresh the XID every time we do an AJAX POST request? Kind of cumbersome.

:(

This is a high priority as all of our addons that use ajax are broken by this!

Brad

       
David Dexter's avatar
David Dexter
88 posts
12 years ago
David Dexter's avatar David Dexter

Hey Guys,

This is a major issue for us as well. Our add to cart / search and various other store related posts are broken by this behavior.

Best, David

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
12 years ago
Pascal Kriete's avatar Pascal Kriete

Thanks guys!

Am I correct in my interpretation that you are using action requests on the backend? I believe that is why it trips up since they’re not considered to be CP requests.

The long term solution here is most definitely an XID refresh when the ajax request returns. I think we can make that mostly transparent on the CP side of things. The frontend is a different story, that may need to be at least semi-manual (some sort of trigger to include the refresh code).

       
David Dexter's avatar
David Dexter
88 posts
12 years ago
David Dexter's avatar David Dexter

Thanks Pascal,

My issue is occurring on the front end with the add to cart form and BR search form.

Best, David

       
Brad Parscale's avatar
Brad Parscale
196 posts
12 years ago
Brad Parscale's avatar Brad Parscale

Hello,

We are indeed sending AJAX requests to the ACT URL from the CP. This worked in EE 2.6 and below perfectly fine with no XID.

Refreshing a XID after each AJAX request is very frustrating. Imagine uploading 10 images with Channel Images, after each image upload I would have to fire another ajax request to refresh the XID.

Security is fine and all but it shouldn’t wreck usability. I believe there should be another way to do AJAX requests from the CP.

Note: We also do AJAX request from the front-end (safecracker) for modules.

Regards,

Brad

       
Derek Jones's avatar
Derek Jones
7,561 posts
12 years ago
Derek Jones's avatar Derek Jones
Security is fine and all but it shouldn’t wreck usability.

Correct it shouldn’t wreck usability, but security against CSRF is not something you should dismiss so easily just because AJAX posting worked without it. CSRF is extremely dangerous. As an example, let’s say that you are a logged in super admin at expressionengineconference.com. Without CSRF protection, If I can get you to visit my site, I can add some JS to my page that will make your browser submit data to your site that would be received with all of your full super admin permissions. Posting new data, deleting members, deleting content, executing queries, etc.

       
Brad Parscale's avatar
Brad Parscale
196 posts
12 years ago
Brad Parscale's avatar Brad Parscale

Derek,

I do understand the need for CSRF protection, I am obviously not against it. But having to do 2 ajax request for 1 is a bit over the top right? I am sure there has to be a better way to do this. Companies like Facebook don’t use this system and I am pretty sure they have figured out a way to prevent CSRF.

So with your current solution I have to do this:

1) AJAX for new XID Code 2) AJAX to upload 1 image (invalidates the XID) 3) AJAX for new XID Code 4) AJAX to upload 1 images (invalidates the XID)

and on and on…

I am pretty sure this only works in CP since the method you use to refresh the XID (I think) only works in the CP. What will I do in SAEF? There I can only do ACT requests and they require a valid XID now.

I hope you understand how frustrating this is for CI, CF, Updater and so on. I am not against improvements and security, but I believe customers will not appreciate the step back in efficiency and speed.

Respectfully,

Brad 😉

       
Derek Jones's avatar
Derek Jones
7,561 posts
12 years ago
Derek Jones's avatar Derek Jones

No, we understand, and we’re pondering solutions. We want this to be both seamless and secure, not one or the other. Current conversation is on how reliant we can be on browsers’ implementations of JS’s domain origin policies.

       
Brad Parscale's avatar
Brad Parscale
196 posts
12 years ago
Brad Parscale's avatar Brad Parscale

Derek,

I can appreciate that… I am hopeful for anything that keeps me from crying over it. 😛

Brad

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
12 years ago
Pascal Kriete's avatar Pascal Kriete

After looking around a bit, it turns out that there is a theoretical csrf attack on ajax requests as outlined here.

So with the same-origin security model out of the question, I’ve gone with a variant of their solution. All ajax requests, regardless of CP or not, will now be expected to provide an X-EEXID header[1]. They will be returned a fresh XID in the same header of the response. I decided to make it header based so we don’t have to worry about exit()’s and injecting objects where strings are sent back.

On the cp side of things this will happen completely transparently as long as you use jQuery’s ajax interface.

Our javascript is essentially doing this:

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
 var old_xid = EE.XID;

 jqXHR.setRequestHeader("X-EEXID", old_xid);

 jqXHR.complete(function(xhr) {
  EE.XID = xhr.getResponseHeader('X-EEXID');

  $('input[name="XID"]').val(function(i, current) {
   return (current == old_xid) ? EE.XID : current;
  });
 });
});

Open to ideas for how to do this on the frontend. It would be easy to add the above snippet to the jquery module output, but not everyone uses that (myself included).

[1] If no header is present, we fall back to POST for backwards-compatibility.

       
Low's avatar
Low
407 posts
12 years ago
Low's avatar Low

Hey guys,

Running into this issue as well with Low Search. The Low Search form allows you to override the global Secure Forms setting, by not generating an XID. Pre-2.7 that worked just fine. No XID posted, no check.

But now, I’m getting the invalid_action message. This is problematic, because lots of times people would perform the search, hit the back button, and search again. That would cause the ‘not authorized’ error message, because the previous XID was already validated and removed. So I built in the secure=”no” setting to make sure no XID is submitted at all regardless of general preferences, avoiding the error altogether. This also is the case if people send the form via Ajax on their front end.

I don’t think there is a csrf security issue with just submitting a search form, right? I’m sure in some cases it’s good to have the secure forms option enabled, but in this case, it’s more of a nuisance then a help, I reckon.

Thoughts?

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
12 years ago
Pascal Kriete's avatar Pascal Kriete

Low,

I think I had a similar issue with our search form. It’s a common place to hit the back button, and the action isn’t destructive.

We added a way to reuse the xid for those cases. Just call this in your action request handler:

ee()->security->restore_xid();
       
Greg Ferrell's avatar
Greg Ferrell
102 posts
12 years ago
Greg Ferrell's avatar Greg Ferrell

So this is something thats definitely not changing and http://ellislab.com/forums/viewthread/236388/#1055730 is the final answer? I have a lot to work on ASAP if so.

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
12 years ago
Pascal Kriete's avatar Pascal Kriete

Greg,

It’s not changing from the perspective that we require an XID for POST requests.

On the backend you shouldn’t have to do anything in the next preview. Do you have a lot of frontend ajax requests? Can we give you a method that injects that bit of jquery in the page? I certainly don’t want every dev to have to copy that bit of JS. On the other hand, I don’t want to just globally inject it on the frontend if it’s not relevant to that request.

A nice middle ground might be to inject it if form_declaration is called.

       
Greg Ferrell's avatar
Greg Ferrell
102 posts
12 years ago
Greg Ferrell's avatar Greg Ferrell

We have a few addons that use ACT ajax for Safecracker, Tag for instance that POSTs to ACT for autocomplete, plus things like Freeform, Super Search, and User, etc that users very often build front-end ajax things with. Since those are outside safecracker and the JS EE object can’t be count on to be present, I will need to send the XID with responses and have the end-users change the XID out on their form.

In those situations, its going to break upgrades for people until they change their templates. We cannot assume that they are always using jQuery, etc, so we are going to need to add instructions for what users are going to need to change to get their templates working again, in addition to us needing to send new XIDs for them.

We are currently doing the XID handling manually on the front end for things like Freeform, User, etc, for when a end-user submits a form and gets errors and wants to use the back button. We just don’t delete the XID until they get past errors. Looking at the code, if I am correct, automatic XID checks on POST are now being run inside of Core->ee_run() before any modules are being called. So we will need to add restore_xid() to those where appropraite because the XID will now be self deleting, where before we were not manually deleting it until a successful POST.

       
1 2

Reply

Sign In To Reply

ExpressionEngine Home Features Pro Contact Version Support
Learn Docs University Forums
Resources Support Add-Ons Partners Blog
Privacy Terms Trademark Use License

Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.