Best ajax questions in March 2012

Is using a for-loop on submitted POST data in PHP safe?

11 votes

I'm always a worry-wart about security in my PHP applications, and I just (potentially) thought of a way a hacker could kill my script. Currently my application takes form data and submits it as an array to a PHP script via AJAX, then loops through this array.

foreach($_POST['form_data'] as $field => $value){
   //Do something here.
}

However, what if a hacker were to forge an AJAX request, and repeatedly submit the 'form_data' array with 100000000000 random elements? The loop would have to iterate through each element, possibly causing a DoS (or at least slow down service), correct?

I'm not entirely educated here, so I may have some incorrect assumptions. Thanks for any input!

This will not be an issue: PHP limits the maximum number of POST vars using the max_input_vars directive, which defaults to 1000 variables.

This limit is actually enforced to prevent a much more serious type of DOS attack than the one you are thinking about (really, iterating a few thousand array elements is like nothing), namely hash table collision based attacks (often referred to as HashDOS). For more info on that issue see my article Supercolliding a PHP array.

What is the best method to make sure two people don't edit the same row on my web app?

6 votes

I have a PHP/jQuery/AJAX/MySQL app built for managing databases. I want to implement the ability to prevent multiple users from editing the same database row at the same time.

  1. What is this called?
  2. Do I use a token system and who ever has the token can edit it until they release the token?
  3. Do I use a "last edit date/time" to compare you loading the HTML form with the time in the database and if the database is the most resent edit then it warns you?
  4. Do I lock the row using database functions?

I'm just not sure which is the best. Assuming between 10 - 15 concurrent users

There are two general approaches-- optimistic and pessimistic locking.

Optimistic locking is generally much easier to implement in a web-based environment because it is fundamentally stateless. It scales much better as well. The downside is that it assumes that your users generally won't be trying to edit the same set of rows at the same time. For most applications, that's a very reasonable assumption but you'd have to verify that your application isn't one of the outliers where users would regularly be stepping on each other's toes. In optimistic locking, you would have some sort of last_modified_timestamp column that you would SELECT when a user fetched the data and then use in the WHERE clause when you go to update the date, i.e.

UPDATE table_name
   SET col1 = <<new value>>,
       col2 = <<new values>>,
       last_modified_timestamp = <<new timestamp>>
 WHERE primary_key = <<key column>>
   AND last_modified_timestamp = <<last modified timestamp you originally queried>>

If that updates 1 row, you know you were successful. Otherwise, if it updates 0 rows, you know that someone else has modified the data in the interim and you can take some action (generally showing the user the new data and asking them if they want to overwrite but you can adopt other conflict resolution approaches).

Pessimistic locking is more challenging to implement particularly in a web-based application particularly when users can close their browser without logging out or where users may start editing some data and go to lunch before hitting Submit. It makes it harder to scale and generally makes the application more difficult to administer. It's really only worth considering if users will regularly try to update the same rows or if updating a row takes a large amount of time for a user so it's worth letting them know up front that someone else has locked the row.

Issue with will_paginate page links

4 votes

I currently have a comment model that posts under a micropost and both are displayed on the same page. The issue is that both are displayed on the same page and both are paginated and I am trying to go for the facebook approach to microposting. Here is the issue below:

The links for both pagination turns into this href="/users/2?page=2" rather than href="/users/2/micropost?page=2" or href="/users/2/comment?page=2". I am unsure how to go about solving this problem. Here are some of my code. All suggestions are much appreciated!

Micropost Render HTML

<table class="microposts">
<% if microposts.any? %>
<%= render microposts %>
<%= will_paginate microposts, :page_links => false %>
<% else %>
<div class="EmptyContainer"><span class='Empty'>Add a thread!</span></div>
<% end %>
</table>

Comment Section HTML

<div id='CommentContainer-<%= micropost.id%>' class='CommentContainer Condensed2'>
<div class='Comment'>
<%= render :partial => "comments/form", :locals => { :micropost => micropost } %>
</div>
<div id='comments'>
  <% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
  <%= render comments %>
  <%= will_paginate comments, :class =>"pagination" %>
</div>
</div>

User Controller for the Show Page

  def show
    @user = User.find(params[:id])
    @comment = Comment.find(params[:id])
    @micropost = Micropost.new
    @comment = Comment.new
    @comment = @micropost.comments.build(params[:comment])
    @comments = @micropost.comments.paginate(:page => params[:page], :per_page => 5)
    @microposts = @user.microposts.order('created_at DESC').paginate(:per_page => 10, :page => params[:page])
      respond_to do |format|
      format.html
      format.js
     end
  end

Problem lies within will_paginate way of creating urls for each page (it doesn't have anything to do with jQuery).

By design, will_paginate try its best to guess what's the base url for the page user is on (internally it's using controller/action to do that). That base url is then combined with any extra params passed to will_paginate helper using :params and succesive page numbers.

For now (will_paginate 3.0.3), in order to overwrite this default behavior, you need to write your custom LinkRenderer class. Below there's example of such class - it makes use of new, extra option :base_link_url that can be passed to will_paginate view helper. Passed string is then used as a base when creating pagination links. If :base_link_url option is not passed, it will fallback to default behavior.

Put following class somewhere rails can find it on load (/lib for example, provided you've added /lib to your autoload paths in application.rb):

# custom_link_renderer.rb
class CustomLinkRenderer < WillPaginate::ActionView::LinkRenderer
  def prepare(collection, options, template)
    @base_link_url = options.delete :base_link_url
    @base_link_url_has_qs = @base_link_url.index('?') != nil if @base_link_url
    super
  end

  protected
  def url(page)
    if @base_link_url.blank?
      super
    else
      @base_url_params ||= begin
        merge_optional_params(default_url_params)
      end

      url_params = @base_url_params.dup
      add_current_page_param(url_params, page)

      query_s = []
      url_params.each_pair {|key,val| query_s.push("#{key}=#{val}")}

      if query_s.size > 0
        @base_link_url+(@base_link_url_has_qs ? '&' : '?')+query_s.join('&')
      else
        @base_link_url
      end
    end
  end
end

Usage:

# in your view
will_paginate collection, :renderer => CustomLinkRenderer, :base_link_url => '/anything/you/want'

And now back to your case. By this time you probably see the solution - you can have two will_paginate widgets on one page with different base urls by passing different :base_link_url options for those two.

How do facebook update content when somebody has posted something

4 votes

I'm really interested on how facebook loads only content when someone else has posted something. The only thing that I can think of is using something like the one below to constantly update the page without reloading the page.

setInterval(ajax_stuff, 1000);

I was watching the console and indeed the request occurs and another new content is added to the page.

enter image description here

I want to be enlightened on how is this done. It would really be awesome if I can use this on a project. I mean doing setInterval every second really consumes much resource. Making a request only when its needed would be the best way to do things. Specifically I want to use it on this project:

https://github.com/anchetaWern/ChatRo

It's basically just a chat box, currently it still uses the setInterval(). I want to update only the content when someone else on the chat session has actually entered something.

I cannot speak directly to how FaceBook does this, but in general, you should be looking at WebSockets.

WebSockets allow the JavaScript on your page to maintain an open connection with a server whereby you can push data out in near-realtime to all of the clients connected to the server.

Take a look at http://pusher.com

Also, google Web Sockets.

Using appendTo and Load in click function

4 votes

jQuery newb and first poster. Please be gentle :-) I've searched and can't find an answer, but I'm sure there's a really simple solution.

Hoping someone can help me. Here's what I'm trying to achieve: I have a row of tabs, with all but the first tab using a click function to load() the external page into the required div. The first tab will have its content loaded by default, not from an external file but from a div already on the page, but further down the code for SEO reasons.

Clicking any other tab loads the content from the external page into the div but if you then want to go back to tab 1, the content is unavailable as it's been replaced by content from the load() - ie no longer in the DOM.

I suppose I could appendTo a #temp div before calling the load() and then append back if tab 1 link is clicked, but there must be a more elegant solution?

Here's code so far:

$(document).ready(function(){

    // default tab1 content div appended to containing div OK
    $("#innerDiv1").appendTo("#outerDiv");

    // tab2 link loads page2.html OK
    $("#link2").click(function(){
        $("#outerDiv").load("page2.html");
    });

    // This doesn't work as it's no longer in the DOM after #link2 clicked.
    $("#link1").click(function(){
        $("#innerDiv1").appendTo("#outerDiv");
    });

});

Any thoughts and replies greatly appreciated.

Thanks in advance M

Change the #link1 click handler to this :

$("#link1").click(function() {
   $("#outerDiv").load('originalurl.html #innerDiv1');
});

this uses AJAX to load the initial page but only grabs the '#innerDiv1' section and the replaces the contents of #outerdiv with it. You will need to replace the originalurl.html with your actual URL ... could maybe use location.href unless you update that for bookmarking ?

Rails JS Response, render both status and template?

4 votes

In my current rails app I'm using an ajax uploader library that requires you respond with json {success:true} to indicate a file was uploaded successfully.

In my app the files are images, and after upload I would like to add this to the page. Normally I would do something like:

respond_to do |format|
  format.html { redirect_to @resource, :notice => 'Created.' }
  format.js
end

In the above example my JS response would render the appropriate template, such as create.js.erb which might say something like...

$('#resources').append('<%= escape_javascript( render '@resource' ) %>');

This is how I have done things like Ajax comments etc. in the past. Now, to get the uploader working my respond_to block currently does this:

format.js { render :json => { :success => true } }

This makes the uploader work but seems to preclude me adding rendered partials to the page like I normally would with an Ajax response.

My question is, is there any way to accomplish both? If not, how would you populate the page with rendered objects after they have been successfully created?

You can't do both directly from the controller or using view templates. It looks like ajax uploader is expecting a response that can be parsed as JSON, so adding any other response using a template (which would mean not doing format.js { render :json => { :success => true }}) will not send back JSON as the response body.

Looking at the source for the plugin, you can see that you can define a method to run onComplete which will give you the JSON response.

This is untested, but should get you close. So you if extend your JSON response like

format.js do
  partial = render_to_string @resource
  render :json => { :success => true, :partial => partial }
end

Then in your javascript on the page when you setup your ajax uploader, add the callback

var uploader = new qq.FileUploader({
  element: document.getElementById('file-uploader'),
  action: '/upload',
  onComplete: function(id, fileName, responseJSON) {
    $('#resources').append(responseJSON.partial);
  }
}); 

JQuery Conflict Ajax Validation Messages Return Location

4 votes

I am having a problem with my jquery form. If you look at this fiddle where I am creating my form, you will notice that after an input field is created, then deleted, the alert messages start popping up on the next element (below where they initially are placed).

To clarify: If the user has not entered any information yet, the alerts pop up in the correct position (floated to the right side of the input field in red text). However, if the user has inputted information, then deletes it, the ajax alert ("this field is required") pops up in the wrong place in the field below where it is supposed to. To view the problem, type in all fields correctly, then delete your name. The message "this field is required" pops up in the email field, but it belongs in the name field.

The js that controls the validation is:

$(document).ready(function() {
    $('#commentForm').validate({
        submitHandler: function(form) {
            $.ajax({
                type: 'POST',
                url: 'process.php',
                data: $(this).serialize(),
                success: function(returnedData) {
                    $('#commentForm').append(returnedData);
                }
            });         
            return false;
        },
        errorPlacement: function(error, element) {
              error.insertAfter( element).position({
                  my:'right top',
                  at:'right top',
                  of:element          
              });
         }  
    }); 
});

EDIT 1: Using Jquery NoConflict mode has not solved this issue. As it appears to be a problem with how the two plugins work together.

EDIT 2: There are actually two solutions to this problem. One is to include the jquery UI script into the head, thereby enabling its 'position' utility to align the error messages at the 'right top'.

The other solution, as noted by a few other contributors, is to modify the css to set

form p {
  position: relative;   /* This ensures error label is positioned within the p tag */
}
label.error {  
  top: 0; /* This ensures that it lines up with the top of the input */
  right:90px; 
  color: red; 
  position:absolute;
}

Thanks for all of the input.

Looks like a styling issue to me (but again, everything does :) with incorrectly used position:absolute, which, btw, cancels out float:left - http://jsfiddle.net/kmJ87/17/

If you're really attached to position:absolute (more styling in the full css, like a nice box message maybe?) you could fix it by adding position:relative to the parent element (paragraph in this case) - http://jsfiddle.net/kmJ87/18/

jQuery: load scripts in order

4 votes

I'm trying load some scripts dynamically with jQuery:

var scripts = ['script1.js','script2.js','script3.js'];

$.each(scripts , function(i, val) {
     $.getScript(val, function() {
     console.log('loaded '+ val);
});

But sometimes the order of loaded scripts changes. How can I load each script after the previous one has successfully loaded?

You can load each after the previous has finished loading by using the callback function of $.getScript() as a recursive function call.

//setup array of scripts and an index to keep track of where we are in the process
var scripts = ['script1.js','script2.js','script3.js'],
    index   = 0;

//setup a function that loads a single script
function load_script() {

    //make sure the current index is still a part of the array
    if (index < scripts.length) {

        //get the script at the current index
        $.getScript(scripts[index], function () {

            //once the script is loaded, increase the index and attempt to load the next script
            console.log('Loaded: ' + scripts[index]);
            index++;
            load_script();
        });
    }
}

What's occurring in your code is that the scripts are being requested at the same time and since they load asynchronously, they return and execute in random order.

Update

I haven't tested this, but if the scripts are hosted locally, then you could try to retrieve them in plain text, then store all of the code in variables until they are all loaded at which time you could evaluate the scripts in order:

var scripts   = ['script1.js','script2.js','script3.js'],

    //setup object to store results of AJAX requests
    responses = {};

//create function that evaluates each response in order
function eval_scripts() {
    for (var i = 0, len = scripts.length; i < len; i++) {
        eval(responses[scripts[i]]);
    }
}

$.each(scripts, function (index, value) {
    $.ajax({
        url      : scripts[index],

        //force the dataType to be `text` rather than `script`
        dataType : 'text',
        success  : function (textScript) {

            //add the response to the `responses` object
            responses[value] = textScript;

            //check if the `responses` object has the same length as the `scripts` array,
            //if so then evaluate the scripts
            if (responses.length === scripts.length) { eval_scripts(); }
        },
        error    : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ }
    });
});

When is it safe to enable CORS?

4 votes

I am developing a JSON/REST web API, for which I specifically want third party websites to be able to call my service through AJAX. Hence, my service is sending the famous CORS header:

Access-Control-Allow-Origin: *

Which allows third party sites to call my service through AJAX. All fine so far.

However, a subsection of my web api is non-public and requires authentication (pretty standard stuff with OAuth and an access_token cookie). Is it safe to enable CORS on this part of my site as well?

On the one hand, it would be cool if third party websites could have ajax clients that also interact with this part of my service. However, the reason that there is a same origin policy in the first place, is that this might be risky. You don't want any website that you visit afterwards to be able to access your private content.

The scenario that I am afraid of is that a user logs in on my web api, either on the website or through a website that he trusts, and he forgets to logout. Will this allow every other website that he vists afterwards to access his private content using the existing session?

So my questions:

  • Is it ever safe to enable CORS on non-public content?
  • If a CORS enabled server sets a session_token through a cookie, will this cookie be saved under the domain of the CORS server or main web-page server?

In answer to your second question (If a CORS enabled server sets a session_token through a cookie...?), the cookie is saved under the domain of the CORS server. The main web page's JS code can't access the cookie, even via document.cookie. The cookie is only sent to the server when the .withCredentials property is set, and even then, it is only accepted when the server sets the Access-Control-Allow-Credentials header.

Your first question is a little more open ended. It is fairly secure, but there are ways to circumvent things. For example, an attacker could use a DNS poisoning technique to cause a preflight request to hit the actual server, but send the actual CORS request to the rogue server. Here are some more resources on CORS security:

http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Cross_Origin_Resource_Sharing

Lastly, your concern is around giving any website access to your CORS data. In order to protect against this, you should not use the Access-Control-Allow-Origin: * header. Instead, you should echo back the user's Origin value. For example:

Access-Control-Allow-Origin: http://www.example.com

This header will allow only http://www.example.com to access the response data.

ajax jquery post, needs some fine tuning for a beginner

4 votes

i'm new to javascript and jquery and as part of a college project i need to make periodic checks the database to see if there has been changes. if there has been changes, i want the result of that change to 'alert' to the screen just to prove the AJAX call is working. i'm using asp.net and c#.

my scenario is: user 'A' logs in and sees user 'B' in a listbox populated by a global list. 'A' clicks on 'B' and clicks the play button. as this happens 'B's' invitedBy column in the User table in the DB changes to 'A'. this is where my problem is, i want to have a script that periodically accesses a web method in my UserDAO.cs class - which has a method that queries the invitedBy column in the DB (this has been tested and works). i'm having trouble getting this working, would someone take a look and see if they can spot anything. all help would be much appreciated!

DBPolling.js

    $(document).ready(function () {
function ajaxRequest() {
    $.ajax({
        type: "POST",
        url: "UserDAO.cs/queryInvitedBy",// is this correct way to input url?
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (resultData) {
            //console.log(result);// i found this in an example...needed?
            if (resultData.status == 'pending') {
                setTimeout(function () { ajaxRequest(); }, 5000); // wait 5 seconds than call ajax request again
            } else {
                var result = eval(resultData);
                alert("You have been invited" + result);
            }
        }
    });
}

});

UserDAO.cs

[WebMethod]
    public string queryInvitedBy()
    {
        // New user
        User user;

        // Open the NHibernate session
        ISession session = NHibernateHttpModule.CurrentSession;

        IQuery q = session.CreateQuery(
            "FROM User WHERE InvitedBy IS NOT NULL");
            // Assign values to the ? placehoders, by their index (0,1, etc.)

        // Make sure List is not empty
        if (q.List<User>().Count > 0)
            // set user to first item in List
            user = q.List<User>()[0];
        else
            // set user to null if none found
            user = null;

        // If no users found, returned user will be blank, otherwise the valid user
        string result = user.InvitedBy.ToString();
        return result;
    }

i've been following online tutorials and looking at Qs similar to mine to get this far, so please let me know if i'm on the right track, or offer a solution if you see any problems.

Call your .aspx page, not the code behind.

url: "UserDAO.aspx/queryInvitedBy",

Sending a post request with HTML comment via AJAX issue

4 votes

I faced the following issue while I submitting my form using jQuery FORM and doing POST submit.

When I type into input field an HTML comment:

< !-- #without space after < symbol

The request never goes submitted and it waits forever.

I believe that the reason is that the HTML comment ruins an XMLHttpRequest object and it never get parsed with PHP. I can just parse out the html comments from input fields before submitting, but something tells me, that its not the best solution to solve this. Does anybody know the best solution to avoid this issue to happen?

The HTML code of my form is the following:

<form method="post" action="/orders/place" class="form a-center" id="orderForm"> 
 <input type="text" x-webkit-speech="" value="Sign text" name="sign" id="sign">
 <textarea rows="7" name="comments" id="comments">Order comments</textarea>
 <p>
  <button id="orderSubmitBtn" class="button" type="submit">
 </p>        
</form>

The Javascript is a simple jQuery form submission:

var options = {
 dataType: 'json',
 success: function(data) { 
   if (data.ok) {
     //do some action here!
   }
 }
};
$('#orderForm').ajaxSubmit(options); 

The only case when it fails is the case when I input an html comment tag.

Also here is the link to the page containing the form http://sandsign.com (Just try entering < !-- text in a sign text a press Lets Go button)

Thanks to RoToRa - I narrowed down my research to PHP script I'm posting to. And realized that it's a bug in Zend Filter class :-(.

The following PHP code with Zend Framework for some reason freezes forever while receiving < !-- as a POST parameter :

$filterChain = new Zend_Filter();
$filterChain->addFilter(new Zend_Filter_StringTrim())
            ->addFilter(new Zend_Filter_StripTags());
$this->getHelper('viewRenderer')->setNoRender();
$signFiltered   = $filterChain->filter($_POST['sign']);

Thanks everybody for advices!