DavidHyogo
DavidHyogo

Reputation: 2896

Advisability of including server-side information in JSON in an Ajax request

I'm working on a materials exchange site for instructors and students. The material is confidential in the sense that it's ours and we don't want other instructors to steal it. On the other hand, it has no personal or sensitive information so security is not a huge concern. If you steal my grammar exercise, I'm not going to sue you. I'm using Ion Auth in a Codeigniter framework and am satisfied with that. I use YUI 2.8 to display editable datatables and editable trees. Building on the Codeigniter MVC framework I have a controller to handle Ajax requests. When I post a request via the YUI Connection class I pass a serialised object called data as the only parameter, which comes from a JSON object assembled on the client side by passing a config object to YAHOO.si.factory.Method like this:

addTreeNode: new YAHOO.si.factory.Method({
    className: "instructors_model",
    methodName: "add_exercise_tree_node",
    key: "id",
    mode: "child",
    fields: ['n0', 'n1','n2', 'n3'],
    params: [{
        key: "nodeData",
        name: "nodeData",
        type: "text",
        direction: "IN",
        value: "34"
    },{
        key: "name",
        name: "name",
        type: "text",
        direction: "IN",
        value: "Grammar"
    }],
    success: "You have successfully added a node to the tree."      
}),

The controller parses the JSON string assembled by YAHOO.si.factory.Method and figures out that it has to call add_exercise_tree_node in the instructors_model and pass 2 parameters. The add_exercise_tree_node method does the dirty work on the database and, hopefully, returns a success message. If so, the success message is displayed on the client side and the tree is updated to include the new node.

My question is, am I giving away too much information about the server in this plain-text querystring? It's a post so it doesn't appear in the URL, but of course it's completely visible in something like the Firebug console.

The question behind that question of course is what do you security experts out there advise about parcelling out responsibility for Ajax in an MVC framework? I want the manageability of having just one controller responsible for handling Ajax requests, so I've ended up with a slightly complicated (and insecure?) overloading on the client-side. What patterns do you advise for this?

Upvotes: 1

Views: 226

Answers (1)

jcolebrand
jcolebrand

Reputation: 16035

My claim in the comments was that you're defeating the purpose of RESTful architecture in the MVC paradigm, primarily with focus on "all AJAX calls go to one controller". So let's tear this down into something usable, and then rebuild our understanding of why/how.

REST just means REpresentational State Transfer but that's not what we mean when we say REST or RESTful. We mean that we intend each URL to represent a type of resource, and we use verbs to indicate what we're doing with each request. So "GET", "POST", "PUT", etc all have a purpose, and we use that purpose to dictate how we interact with the individual resources.

So let's put that into perspective, let's do something with that; consider an HR application (this is one of those easy ones that people adopt). We have People and Departments. Departments have an ID, a Name, and a Manager (who is a Person). People have an ID, a Name, a Manager (may be -1 in our system to indicate no manager, or an ID of a person) and a Phone Number.

When we HTTP GET http://server.domain/app/Person we get a directory of all people, that gives us their name and ID.

[ {Name: "Cole Brand", ID: 1}, {Name: "user341180", ID: 2} ]

When we HTTP GET http://server.domain/app/Person/1 we get

{ Name: "Cole Brand", ID: 1, Manager: -1, "Phone Number": "222-555-1234" }

When we HTTP GET http://server.domain/app/Person/2 we get

{ Name: "user341180", ID: 2, Manager: 1, "Phone Number": "222-555-6789" }

And just for the sake of completeness, a list of departments:

HTTP GET http://server.domain/app/Department/

{ Name: "HR", Manager: 1 }

Now obviously, my example is a little dry, because for instance, the employees certainly work in a department, but I haven't associated them to it by their profile. Surely the database would track that, but we don't have it here. This is a simple example.

So you can see from this that there is no HTML being returned. We will come back to that.

For the next part, notice that I've kept using HTTP GET. What if we used HTTP POST? That would mean that whatever we passed, would overwrite that data. So let me give a brief example:

HTTP POST http://server.domain/app/Person/2

send this data in the post body { Manager: -1, "Phone Number": "222-555-0089" }
get nothing in response (we could return the object, but my API doesn't for whatever reason, call it a specification deficiency)

When we HTTP GET http://server.domain/app/Person/2 we now get

{ Name: "user341180", ID: 2, Manager: -1, "Phone Number": "222-555-0089" }

See how we used HTTP POST to update the record? That's how we use our RESTful methods, we use the verb to indicate the action.

So what else could we use to communicate with the server? What if we wanted to have the RESTful methods return both a webpage and the data, but for GET? We could use an HTTP HEADER (maybe an X-Header?) to specify that we're making a data call, so by default we make a request to HTTP GET http://server.domain/app/Person/1 and we get a webpage. If you would like an example of that (a rest response providing a webpage) check the page we're on now. https://stackoverflow.com/questions/11061912/ <-- is actually served by MVC restful principles (but I don't think they supply the JSON by this method, because that's not how their system is setup).

So I'm probably scrambling you all up, I just wanted to review REST, and how we use it today for MVC purposes. Let's look at part of that again, the part where we do http://server.domain/app/Person

In MVC terms, that would mean that we've got a Person controller in our app. Any requests made against the Person controller would be routed based on their verb type first, then any additional parameters next. For instance, submitting this answer makes a post to https://stackoverflow.com/questions/11061912/answer/submit. So the Controller knows that it expects to receive "Post ID" (so it knows the parent that the answer belongs to), "answer" telling it that I'm adding an answer, and "submit" so it knows what I'm doing. If I were editing it would be an edit-submit instead of answer/submit.

Ok, so I feel like I'm making things confusing, and I don't know if you read my answer on MVC in node and general: How are models tied to views? but let me clarify: The Controller is a routing device to take input, send it to the appropriate model, and then render some view (HTML, JSON, XML, plain text, etc). Note that rendering a view is not required (remember my crappy API that didn't return anything on a HTTP POST?).

So now we get to the point of what I was trying to get at in my response earlier, which I'm still not being clear enough on. When you move methods from the "appropriate resource" (in the case of this post /question/), you're breaking the idea that one URL root is one resource. Oy, I've messed this all up haven't I?

In REST principles, each URL-root is one resource. You can do things from that resource, like rendering a certain view based on some bit of data, or you can add/modify data using a certain verb, or you can make flapjacks if that's your style. But all Person will always be at http://server.domain/app/Person, and not "some person commands are on http://server.domain/app/Person and some person commands are on http://server.domain/app/Department" because then you're just going to throw your arms up in the air and go "well how do I know where all to find people actions?!?!"

That, in a nutshell, is why you don't want to put some methods for accessing data on one controller (rendering the view) and some methods for accessing data on another controller (JSON) for the same resource-type.


Now that I've put all that braindump into a post, which parts am I fuzzy on? Feel free to edit the post and insert some **what do you mean here?** or **you seem to be jumping around on this point a lot** or whatever you feel is appropriate.

Upvotes: 6

Related Questions