Sails.js: How to properly handle request parameters/queries to backend? - http

I'm developing an application using Sails.js in the backend, and I'm having trouble validating requests as follows:
I want to block access to certain resources based on an attribute of the logged in user. I have the REST API blueprints enabled, and the shortcut routes disabled. I have the following piece of code:
User.findOne()
.where(query)
.exec(function(err, user) {
if (user.team !== req.user.team) {
return res.view('403');
}
return next();
});
where query is the criteria by which I'd like to do the database search. The idea is that the user can only access the requested user if they're in the same "team".
The problem is that the user can make at least the following kinds of requests to the backend, maybe more (I'm not too experienced with sails, please enlighten me if there's even more types):
localhost:1337/user?id=1
In this case, the req object will have a req.query attribute, which I can pass on as query as it is. Now, the following kind of request is also possible:
localhost:1337/user/1
Here req.query will be an empty object, while req.params is [ id: '1'].
Now this is troublesome; if I understand correctly, the the type of req.params isn't a JSON object, so I can't pass it as query as it is. In addition, I'd have to convert the id parameter into Int since it's originally a string for some reason (?).
What I'm asking is if there's a way I may have missed that handles both kinds of requests in the same way, or whether I'll have to take both cases into account in a way like
var query = isEmpty(req.query) ? req.params : req.query
in which case I'd have to convert req.params into something I could pass to the database search and would generally be troublesome and inconvenient. I'd like to know what the best way to handle this situation is.

Well, it's funny how right after posting a question you happen to find an answer. Apparently there's a function called req.allParams() which "Includes parameters parsed from the url path, the query string, and the request body." according to the official docs. I've no idea how I never bumped into this before, but now I did and it seems to work, so hooray!

Related

Simulate previous request

In my application there are sometimes in that I want to get a user request, save it in some place and then, in a next request, simulate saved request instead of real request, is that possible?
Use any web debugger. I use Fiddler 2.6.2 myself.
Find it here, https://www.telerik.com/download/fiddler
Be warned - there is no robust way to do it (there are a lot of edge cases to consider) but hopefully this will get you started:
Take Request.Form.ToString() and save it against the user somewhere. For testing I suggest putting it in a hidden field, but at some point you would probably need to move that to a database and associate that with the user somehow.
You will need to have a field that will tell you whether the previous request should be replayed. Using a query string parameter like ?replay=true will work. Then pull it into your page:
protected bool IsReplayRequest
{
get
{
return bool.Parse(this.GetValue(p => p.Request["replay"], "false"));
}
}
To simulate the request you will need to override the page's DeterminePostBackMode. This is one of the first methods ASP.NET calls to start the postback process. Use the saved request form converted into a NameValueCollection. Something like this:
protected override NameValueCollection DeterminePostBackMode()
{
if (IsReplayRequest && SavedFormData != null)
{
if (!string.IsNullOrWhiteSpace(SavedFormData.Data))
{
return HttpUtility.ParseQueryString(SavedFormData.Data ?? string.Empty);
}
}
return base.DeterminePostBackMode();
}
Where SavedFormData is just a class which holds the request form and the user information.
With those 3 steps, you should be able to succesfully simulate a previous request for a simple page
Now for the potential problems:
First, the viewstate might get in the way. If you have any listboxes or data grids or authentication etc, you will then need to save the viewstate with the form data. for that you will need to override the page GetStatePersister() method (Is it possible to make a custom implementation of ViewState?).
Second, once you have simulated a request, you need to make sure a) no data is corrupted and b) you remove the "replay" query string. Otherwise the request will play over and over again.
Third, depending on how you store the request form, you will have to think about how to associate it with the user/browser/session/window. Dealing with each one of those has it's own problems.
Once you've got everything above solved, you will successfully simulate a saved request!

Symfony2: Access Request object in Entity

I'd like to know how to access the Request object in an entity (Symfony2) to modify the user locale.
If someone has found a solution for my problem, please let me know.
It's not possible. This is by design: the entity is just a simple object that should know nothing about the request - it's the responsibility of the controller to interpret the request, and manipulate the entity based on that.
Something like:
//inside your controller:
public function fooBarAction(Request $request)
{
$entity = // get entity
$entity->setLocale($request->getSession()->getLocale());
}
The above is just example code, it won't work if you just copy and paste it. It's just to demonstrate the general idea. The entity should just be a very simple object, who's only responsibility is to hold some data. It shouldn't know where the data is coming from - that keeps it flexible (if you want to set the locale based on something else, you only have to change your controller, not all your entities).
It is possible, but...
What you can but never should do is inject the Request object into the entity (Practically turning your entity into service, see here). Also, even worse idea (but which people still do), you could inject the whole container and get Request from there. The reason why you shouldn't do it is you never should have any code that deals with business rules or any system code in your entities.
You can switch your locale directly in your routes by using _locale custom variable (accessible also from the Request). Or you can create a kernel listener, which will do the required functionality for you. This way you keep your code testable and decoupled.

How to pass multiple objects using RedirectToAction() in Asp.NET MVC?

I would like to pass multiple objects using redirectToAction() method. Below is the actionresult i'm redirecting to.
public ActionResult GetEmployees(Models.Department department, Models.Category category, Models.Role role)
{
return View();
}
I'd like to do something like the below
public ActionResult test()
{
Models.Department dep = new Models.Department();
Models.Category cat.......etc
return RedirectToAction("GetEmployees", dep, cat, role); }
Any help would be greatly appreciated - thanks
Updated
Can I use something like
Models.Department dep = new Models.Department() { DepId = employee.DepartmentId };
Models.Category cat = new Models.Category() { CatId = employee.JobCategoryId };
Models.Role title = new Models.Role() { RoleId = employee.JobTitleId };
return RedirectToAction("GetEmployees", new { department = dep, category = cat, role = title });
You cannot pass objects to the RedirectToAction method. This method is designed to pass only parameters. So you will need to pass all the values you want to be emitted in the corresponding GET request:
return RedirectToAction("GetEmployees", new
{
DepId = dep.DepId,
DepName = dep.DepName,
CatId = cat.CatId,
RoleId = role.RoleId,
... so on for each property you need
});
But a better way is to only send the ids of those objects:
return RedirectToAction("GetEmployees", new
{
DepId = dep.DepId,
CatId = cat.CatId,
RoleId = role.RoleId
});
and then in the target controller action use those ids to retrieve the entities from your underlying datasore:
public ActionResult GetEmployees(int depId, int catId, int roleId)
{
var dep = repository.GetDep(depId);
var cat = repository.GetCat(catId);
var role = repository.GetRole(roleId);
...
}
This is not an answer, per se, but I see questions similar to this all the time that boil down to a fundamental misunderstanding or lack of understanding about how HTTP works. This is not a criticism, many web developers think that all they need to know is HTML, JavaScript and CSS to make a website, but they neglect to see the need to actually understand the platform their code is running on. Look at it this way: you wouldn't sit down and start writing an app without understanding your target platform (Windows, Mac, iOS, Android, etc.). You'd have to know how each handles memory, garbage collection, storage, etc., in order to write anything that would amount to anything.
The same applies to the web. It's a distributed platform, but a platform nonetheless, and it's important to understand how the underlying structure works. I obviously won't go into extreme detail on this here. There's entire volumes on HTTP and associated technologies. For more information, I highly recommend picking up something like O'Reilly's HTTP: The Definitive Guide.
As for your problem here, HTTP implements various "verbs", the most common of which are GET and POST. Simplistically, GET is a non-volatile request for a resource to be returned, while POST is volatile (changes will be made, resources deleted, etc.). With GET there is no request "body". A request can be composed of various parts, a URL, headers, and a body. In a POST, the posted data would constitute the request body, but GET does not have posted data and therefore no request body. Now, again, we're speaking simplistically here. You might wonder about the querystring. Would that not be "posted data"? Technically, yes, it can be, but again, technically, anything in the URL (or if we really want to be exact, the URI) is a piece of identifying data for an existing resource. When you make a search on Google, for example, your search query will be appended to the URI for the search results page. This is posted data (you posted the query), but it's not just data, the URI with the query string gives the location of the resource that corresponds to that exact query. Someone else who entered the same query would be sent to the same URL.
That was a bit of a tangent, but it's important to understand that a querystring is not a way to pass unrelated data. The querystring is part of the URI so the exact page loaded with two different querystrings is two entirely different resources.
Moving on, a redirect is not some special type of request (in the sense of being represented by a different HTTP verb); it's merely an instruction to the client's browser that it should issue another GET request to the specified URL. You don't get any control over what verb is used: it's always GET. So, you can't pass anything along for the ride. If you have objects that will be represented by the URI being redirected to, then obviously you would pass the identifying information required to retrieve them (id, slug, etc.) using either the URI path and/or querystring. If there's any data not directly related to the resource being represented, that data must go in some other type of storage system, such as the session.

how to disable reaching ajax call from browser

I have following ajax call
open: function () {
$(this).load("MyBox.aspx?sec=L&levId=" + RowId);
}
so people can see the querystring, so the user can copy url and paste it to browser but how can i block that? I dont want it to shown from browser. How I can do that? I m using asp.net and jquery.
load function issues a GET request. Instead of that, you may use a jQuery POST call and get the data. Users can't get the result by pasting it in browser and hit enter (which is GET request)
var thatObject=$(this);
$.post("MyBox.aspx?sec=L&levId=" + RowId,function(response){
thatObject.html(response);
})
In the server page, you can read the values posted by checking the Request.Form collection (instead of Request.QueryString).
from msdn
The Form collection retrieves the values of form elements posted to
the HTTP request body, with a form using the POST method.
You can determine whether the call is a GET call or POST call by inspecting the Request.RequestType property value. This way you can avoid people issuing GET request to this method and getting the response.
But remember that, there are tools/browser addons which does the POST request from browser.
Also if the data is for authorized users, you may check the user is authorized to access it in the server page(MYbox.aspx) before returning the content.
You can't. You can never trust any code running on the client. If you need to hide data on the client, you should create a server based session and then put a session token in an encrypted cookie.
From wikipedia and W3C
Some methods (for example, HEAD, GET, OPTIONS and TRACE) are defined as safe, which means they are intended only for information retrieval and should not change the state of the server. In other words, they should not have side effects, beyond relatively harmless effects such as logging, caching, the serving of banner advertisements or incrementing a web counter.
Making arbitrary GET requests without regard to the context of the application's state should therefore be considered safe.
By contrast, methods such as POST, PUT and DELETE are intended for actions that may cause side effect
If your get request changes the state of the server (which it most likely does based on your post), you are doing something wrong. What you're trying to do is impossible. You need to rethink your architecture.

Prevent query string manipulation by adding a hash?

To protect a web application from query string manipulation, I was considering adding a query string parameter to every url which stores a SHA1 hash of all the other query string parameters & values, then validating against the hash on every request.
Does this method provide strong protection against user manipulation of query string values? Are there any other downsides/side-effects to doing this?
I am not particularly concerned about the 'ugly' urls for this private web application. Url's will still be 'bookmarkable' as the hash will always be the same for the same query string arguments.
This is an ASP.NET application.
I'm not sure this provides any sort of security. If a man-in-the-middle attacker wants to change the parameters, all they must do is change the query string and recompute the SHA-1 hash and send that request along to the server.
For example, the URL sent by the browser might be:
http://www.example.com/addUser.html?parameterA=foo&hash=SHA1("parameterA=foo")
If an attacker intercepts this, they can edit it in this way:
http://www.example.com/adduser.html?parameterA=bar&hash=SHA1("parameterA=bar")
Really, this boils down to the fact you can trust the hash only as much as the parameters themselves.
One way you could fix this would be if the user has a password that only they and the server knows, then it would be impossible for the attacker to recompute the hash if they change the parameters. For example:
http://www.example.com/addUser.html?parameterA=foo&hash=SHA1("parameterA=foo"+"theuserpassword")
But don't put the password as one of the parameters in the URL :)
It is important to note that this isn't the state of the art for verifying the integrity of messages passed between two parties. What is used today is a form of the Hash-based Message Authentication Code (HMAC) algorithm, which is pretty well described in HMAC, and definitively in RFC2104 and FIPS Pub 198-1.
My solution to prevent query string manipulation with no hash:
In the global.asax file
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// I take the url referer host. (manipulating the query string this value is null or your local address)
string strRefererHost = Request.UrlReferrer == null ? string.Empty : Request.UrlReferrer.Host;
// This is the host name of your application
string strUrlHost = Request.Url.Host;
// I read the query string parameters
string strQSPars = Request.Url.Query ?? string.Empty;
// If the referer is not the application host (... someone manipulated the qs)...
// and there is a query string parameter (be sure of this otherwise nobody can access the default page of your site
// because this page has always a local referer...)
if (strRefererHost != strUrlHost && strQSPars != string.Empty)
Response.Redirect("~/WrongReferer.aspx"); // your error page
}
You might consider using this little open source library:
http://www.codeproject.com/KB/aspnet/Univar.aspx
It uses a unique key for each client computer and comes with many other goodies.
I think is a good idea to add a parameter with a hash of all the other parameters. It prevents radically the querystring manipulation, but you have to think about the problem that means use those URLs in other pages of your application, send those URLs to the public or use them in any printed way. You need to have a very good way to order and to have them at hand speccially if those pages are not dynamically created, or if you just need to add those URLs by hand.
I don't see any other problem about it. Some one may tell you that the hash can be calculated, but you can play with the order of the parameters obtaining different hashes and making very difficult to guess.
One major problem with this is that javascript would have to do client-side SHA calculations just to link to pages, this of course depends on how much you use JS but it shouldn't be unresonable to think that a get argument might include pageNo=1, and to have a 'jump to page' input box, this would be made difficult if you add a hash. You could store in a session (server side) anything that you really don't want manipulated.

Resources