Restricting access when user changes the link directly Cakephp - url

I am really new in cakephp. I want to know how to restrict the user from opening pages such as Users for example when the user changes the url. Well, I am not good at telling my own problems so here:
for example: the user id is 1 so when he viewed his own details it should be something like users/view/1, but i dont want that user to view user # 2 when he changes the url to users/view/2. I hope you undersand. Thanks in advance!

assuming you have the current looged in user data store in a session somewhere.
the idea is to compare it against the passed id in the url
---- in your UsersController.php
public function view($id){
if($this->Session->read('User.id') != $id ){
// cannot continue...
// possibly redirect....
}
}

The solution can be found via google:
http://www.dereuromark.de/2011/10/05/common-cakephp-problems-and-solutions/
Basically, you get the current id from session:
$uid = $this->Session->read('Auth.User.id');
And compare it against the record you are displaying/editing.
If they don't match, you throw a NotAllowedException().
Protip: Don't append the id for edit/view etc, if it's the user's own profile or if it can only be viewed by the owner.
Same way you obtain the ID above for validation, you can also use this session user id to get the correct record in the first place.
Also, don't put the id into the view (forms) - not even as hidden field - but inject it into the data array prior to saving/validating.
You can also see a current CakePHP 2.4 implementation here - which can also be seen/tested live via corresponding website.

Related

MVC best practice passing IDs across views

I am just starting MVC and I would like to know the best practice to pass sensitive information like IDs across views ...
Let's assume that I have a scenario.
I have a car service managing MVC application which allow users to choose product for their registered car.
The user have to register their car first before they choose a product for their service.
In register view, they fill out the car detail and it redirects to purchase product page when they click the submit button. At the time when they click the submit button, we store car details with user ID (which I can get from Identity) and generate unique car ID from the database. I want to pass this newly created car ID to next view.
In purchase product page, they can choose different product A or B and when they choose, it redirects to checkout page.
What I want to achieve now is then in checkout page, how securely we can carry the car ID that user get after they have registered their car and product ID from previous product view so I can process transaction with userID, carID, and productID.
Is Session way to go with this ? Or any other better way to tackle this problem .?
Someone with small example will be great help for me.
Thanks,
In your example given I would certainly recommend storing the ID in a session. The web is a stateless beast, and what you're essentially after doing is recording state for the duration of the user's visit to the website/application - this is essentially what sessions are designed to do.
Creating, storing and retrieving data from a session is simple and can be done like so:
Setting a variable in the session object
[HttpPost]
public ActionResult Login(int carId)
{
...
Session["carId"] = carId;
...
}
Retrieving a variable from the Session object
public ActionResult Load()
{
...
int carId = Session["carId"];
...
}
Whilst this is a basic example, it gives you an idea as to how to store/retrieve simple types of data from a session.
For storing more information such as large objects you can use the [Serialize] class attribute outlined in my answer in this post.

Deployd : Most secure, most elegant way to get all objects in a specific collection created by the logged-in user?

I think the title pretty much says it all... Brand new to Deployd, so any pointers about how best to go about this are appreciated.
To get the objects in a collection created by the user (I assume you're using the javascript library dpd.js):
// Get the current user:
var currentUser;
dpd.users.me(function(result, error) {
currentUser = result;
});
// query your collection with your currentUser id as parameter
dpd.yourcollection.get({creator:currentUser.id}, function(result) {
// Do something with the result
console.log(result);
});
Your collection should have a property "creator" that contains the id of the user who created the object (*).
Then, to secure your backend, go to the dashboard, in the ON_GET tab of your collection and secure it with this code:
cancelUnless(isMe(this.creator), "You have to be the creator to view this item", 401);
More info about cancellUnless() and isMe() here:
http://docs.deployd.com/docs/collections/reference/event-api.md#s-cancelIf%28%29,%20cancelUnless%28%29-764
The good practice to secure your collections is to allow queries only if user is logged:
cancelUnless(me,"You have to be connected to view this item", 401);
Users collections should be particularly well secured (allow ON_PUT only by admin or something like that).
*: to automatically store the currentUserId in the creator property, you could also add this in the ON_POST event in the dashboard:
this.creator = me.id;
More info here: http://docs.deployd.com/docs/collections/reference/event-api.md#s-me-764
As of version 0.8.9, event ONBEFOREREQUEST exists and you could just put this code in there:
cancelUnless(me);
query.creator = me.id;
This means that for every request sent to that endpoint, creator key would be queried to have the currently logged in user's id. If there's not currently logged in user, the request is canceled.

Can user change input from readonly to editable?

I'm using MVC for my data entry form and I have the following div:
<div>
<label>Bar Code:</label>
#if (Model.GiftCardId == default(int))
{
#Html.TextBoxFor(model => model.BarCode)
}
else
{
#Html.TextBoxFor(model => model.BarCode, new { #readonly="readonly"})
}
</div>
Here, I'm making sure that if the user is entering a new gift card, an editable input is displayed to allow the user to enter a new bar code. But if the user is editing an existing gift card, the input must display as a readonly input. My question is: can the user alter the readonly attribute of the barCode input and allow himself to enter a different one? The BarCode field is not the primary key in the table but it must be unique. I use the GiftCardId field to identify the record. But then, what's to stop the user from changing the GiftCardId as well when submitting the form? How can this be controlled?
I understand this to be a security-related question: ie. can the user hack the form to do something with it that you didn't intend.
The answer is yes, a user can use tools like Firebug to interfere with the markup, thereby changing the readonly attribute.
You don't show how the GiftCardId is collected from the user. Assuming it is collected and validatated in a previous view / action method, a more secure approach would be to redirect to a different view depending on whether the GiftCardId is valid / new or not.
Edit after comments
A couple of suggestions.
Store the GiftCardId in session state rather than send it to the browser.
Use a one-way hashing function to generate a token from the GiftCardId and send it to the browser in a hidden field. Rehash the GiftCardId that is posted back and check that it matches the original hash. See this short article on creating an MD5 hash.
simple answer is "Yes", all request can be forged, that's why you should never trust user inputs and validate the user inputs on the server side.
What you can do really depends on what you needs and the implication of the GiftCardId been modified. Things you could do in addition to the server side validation,
1. hide the field instead of making it visible
2. encrypt the GiftCardId

Where to store common action parameter data in asp.net mvc application

Our web application needs one common parameter in every action method.
In our case it is the customer account id and we need to support the following scenarios
a. A group of users might have the same account id which can be derived from the user profile.
b. Customer Support team should be able explicitly supply the account id of a customer and also should be able to switch the account on any page
We are trying to not to use asp.net session to store this kind of data.
Are there any other options to store and manage this kind of common parameter data?
Write it out as an ecrypted value to hidden field on your master page and supply the value to every view. When the user is in a a customer role, place a change account "control" on the page that is able to retrieve and update the account data -- via AJAX, perhaps -- to change the current account id. It might be easiest to do this with a custom base controller which gets the data via the ValueProvider directly and stores it as a property on the page rather than having it be a parameter to every method.
Use Routing for the value. So if you need to change the id you can use another URL or post it as a parameter.
Whenever you need the value just ask the ValueProvider for it.
In case it is blank - use the one from user profile.
Of course you'd better write small method that will do just that:
// Register route like:
route.MapRoute("ProvidesAccountId", "{controller}/{id}/account{accountId}/{action}.aspx")
// Property on the base controller
protected Account CurrentAccount {
get {
var accountId = ValueProvider.GetValue<int?>("accountId"); // GetValue is just a helper
if (accountId.HasValue)
return YourRepositor.GetAccountBy(accountId.Value);
return CurrentUser.Account;
}
}
Not to use current user's account hit the URL: Profile/123/account/Edit.aspx
To use another account you can hit the URL: Profile/123/account-456/Edit.aspx
You get the idea.
Cheers,
Dmitriy.

When to use TempData vs Session in ASP.Net MVC

I am trying to get the hang of MVC framework so bear with me.
Right now, the only thing I'm using the session store for is storing the current logged in user. My website is simple. For this example, consider three domain objects, Person, Meeting, and File. Users can log in and view a "members only" profile of a meeting and can add files to it, or view a meeting's public "profile" if they aren't logged in.
So, from the meeting's private profile, with a logged in user, I have a "add files" link. This link routes to FileContoller.Add(int meetingId). From this action, I get the meeting the user want to add files to using the meeting id, but after the form is posted, I still need to know which meeting the user is adding files to. That's where my question lies, should I pass the "currently interacting with" meeting through TempData, or add it to the Session store?
This is how I currently have the Add action setup, but it's not working:
public ActionResult Add(int meetingId)
{
try
{
var meeting = _meetingsRepository.GetById(meetingId);
ViewData.Model = meeting;
TempData[TempDataKeys.CurrentMeeting] = meeting; /* add to tempdata here */
}
catch (Exception)
{
TempData[TempDataKeys.ErrorMessage] = "Unable to add files to this meeting.";
return RedirectToRoute("MeetingsIndex");
}
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
var member = Session[SessionStateKeys.Member] as Member;
var meeting = TempData[TempDataKeys.CurrentMeeting] as Meeting; /* meeting ends up null here */
if (member == null)
{
TempData[TempDataKeys.ErrorMessage] = "You must be logged in to add files to an meeting.";
return RedirectToRoute("LoginPage");
}
if (meeting == null)
{
TempData[TempDataKeys.ErrorMessage] = "An error occurred. No meeting selected.";
return RedirectToRoute("MeetingsIndex");
}
// add files to meeting
TempData[TempDataKeys.Notification] = "Successfully added.";
return RedirectToRoute("AddFiles", new {meetingId = meeting.MeetingId});
}
Edit:
Based on most of the answers, can any one provide any examples on what kind of data (other than messages) should be stored in TempData vs Session?
TempData is session, so they're not entirely different. However, the distinction is easy to understand, because TempData is for redirects, and redirects only. So when you set some message in TempData and then redirect, you are using TempData correctly.
However, using Session for any kind of security is extremely dangerous. Session and Membership are entirely separate in ASP.NET. You can "steal" sessions from other users, and yes, people do attack web sites this way. So if you want to selectively stop a post information based on whether a user is logged in, look at IsAuthenticated, and if you want to selectively show information based on what type of user is logged in, you use a Role provider. Because GETs can be cached, the only way to selectively allow access to an action in a GET is with AuthorizeAttribute.
Update In response to your edited question: You already have a good example of using TempData in your question, namely, returning a simple error message after a failed POST. In terms of what should be stored in Session (beyond "not much"), I just think of Session as a user-specific cache. Like the non-user-specific Cache, you should not put security-sensitive information there. But it's a good place to stick stuff which is relatively expensive to look up. For example, our Site.Master has the user's full name displayed on it. That is stored in a database, and we don't want to do a database query for it for every page we serve. (An installation of our application is used in a single company, so a user's full name is not considered "security-sensitive.") So if you think of Session as a cache which varies by a cookie which the user has, you won't be far wrong.
The default TempData provider uses the session so there really isn't much of a distinction, except that your TempData is cleared out at the end of the next request. You should use TempData when the data needs only to persist between two requests, preferably the second one being a redirect to avoid issues with other requests from the user -- from AJAX, for example -- deleting the data accidentally. If the data needs to persist longer than that, you should either repopulate the TempData or use the Session directly.
You can use it as per your requirement. A clarification can be,
TempData Vs Session
TempData
TempData allow us to persisting data for the duration of single subsequent request.
ASP.net MVC will automatically expire the value of tempdata once consecutive request returned the result (it means, it alive only till the target view is fully loaded).
It valid for only current and subsequent request only
TempData has Keep method to retention the value of TempData.
Example:
TempData.Keep(), TempData.Keep(“EmpName”)
TempData internally stored the value in to Session variable.
It is used to stored only one time messages like validation messages, error messages etc.
Session:
Session is able to store data much more long time, until user session is not expire.
Session will be expire after the session time out occurred.
It valid for all requests.
N/A
Session varible are stored in SessionStateItemCollection object (Which is exposed through the HttpContext.Session property of page).
It is used to stored long life data like user id, role id etc. which required throughout user session.
TempData and session, both required typecasting for getting data and check for null values to avoid run time exception.
"It doesn't work" isn't very descriptive, but let me offer a couple suggestions.
Under the hood, TempData uses Session to store values. So there isn't much difference in terms of storage mechanisms or anything like that. However, TempData only lasts until the next request is received.
If the user makes an ajax request in between form posts, TempData is gone. Any request whatsoever will clear TempData. So it's really only reliable when you're doing a manual redirect.
Why can't you just simply render the meeting ID to a hidden field in your View form? You're already adding it to the model. Alternately, add it to your route as a parameter.
I prefer to maintain that kind of data in the page itself. Render meetingID as a hidden input, so it gets submitted back to the controller. The controller handling the post can then feed that meeting ID back to whatever view will be rendered, so that the meetingID basically gets passed around as long as you need it.
It's kind of like the difference between storing a value in a global variable before calling a method that will operate on it, vs. passing the value directly to the method.
I would suggest MvcContrib's solution:
http://jonkruger.com/blog/2009/04/06/aspnet-mvc-pass-parameters-when-redirecting-from-one-action-to-another/
If you don't want full MvcContrib, the solution is only 1 method + 1 class that you can easily grab from MvcContrib sources.
The TempData property value is stored in session state. The value of TempData persists until it is read or until the session times out. If you want pass data one controller view to another controller view then you should use TempData.
Use Session when the data need for the throughout application

Resources