I am writing an application in asp.mvc. I have a view that displays a Product with specific id and on with that view user can modify the Product. There is a dropdown list with colors, that user can select. Range of available colors depends on user's permissions, not all users have access to all colors.
When user clicks "Save" button an ajax request us sent to server with ids of Product and selected color.
Here is the problem:
When user opens the page I check if he is authorized to edit the product with id provided in url and I display only those colors that user can access. But I have no guarantee that user modifies the ajax request sent when he saves the Product. So I can display Product with id 1, and colors with id 12, 13, 14, but user can manually alter the request and change Product id to 3 (which he is not permitted to edit) and select color to 15 (which he shouldn't even see).
In good old webforms this wasn't a problem, because id of product could have been saved in viewstate, and on server side I checked which index of dropdown was selected and then I knew what is the id of selected item (stored in viewstate or controlstate). How do you solve this problem in MVC? Do I have to check if user has access to each element twice, when I display the data and when I receive it, for example in "Save" request?
Even ViewState without protection and care can expose your web server to malicious content. Please note:
Because it's composed of plain text, the view state could be tampered with. Although programmers are not supposed to store sensitive data in the view state (credit card numbers, passwords, or connection strings, for example), it goes without saying that the view state can be used to carry out attacks on the server. View state is not a security hole per se, but just like query strings and other hidden fields you may have used in the past, it's a potential vehicle for malicious code. Since the view state is encoded, protected, and validated, it does provide more security features than other hidden fields that you may use for your own programming purposes.
as Dino Esposito states here.
You've got three options:
Protect (encrypt) your hidden fields (current productId and colors) and validate them on server after a user posts.
Use sessions (store current user's working context, i.e. productId and colors), in case option 3 is too resource consuming or you don't want to maintain huge amount of validation logic on server.
Validate permissions for the objects after user posts. In case option 2 cannot be accepted (you don't use sessions at all).
I agree with RononDex's answer. Session provides you with an easy means of storing data on the server for the user, without exposing that data in way they can manipulate.
So you could store the product ID like so:
Session["ProductId"] = however you get the id.
Plus you can store the colours:
Session["Colours"] = // Whatever you want, an array of int or List<int>
There are caveats with session state though, including that it can be wiped, be it by an expiration of that session (which you can control the number of minutes before that takes place), or an application pool refresh, so bear that in mind.
This might also be good reading for you:
http://brockallen.com/2012/04/07/think-twice-about-using-session-state/
So there are pros and cons to session state. If you decide to not use session state, and instead store the ID values in hidden fields in the HMTL, then please do consider hashing, or encrypting, those ID values so that a user cannot see what they are, or try to alter them.
TempData is used in cases to maintain state, it is stored on the server for one user request.
Related
I have two fields in SAP Fiori App: Template_ID and Offer_ID.
I want to choose value in Offer_ID depending on Template_ID field value.
For solving this problem I've tried to do this steps:
When the user click on Template_ID field in Back-End runs the method:
CL_CUAN_CAMPAIGN_DPC->contentset_get_entityset().
This method has returning paramater et_result. In et_result I have the necessary field temp_id.
For saving temp_id value I created a global attribute in class ZCL_CUAN_CLASS.
ZCL_CUAN_CLASS=>GV_CONTENT = VALUE #( et_result[ 1 ]-temp_ID OPTIONAL ).
I'll use this global attribute as an input parameter for my second method:
CL_CUAN_CAMPAIGN_DPC->GET_OFFER_BY_TEMPLATE().
This method returns to me the internal table with the offer_id, which belongs to my choosen temp_id.
But when the user click on Offer_ID field on Web UI, in debugging I see that my global attribute is blank.
May be it's because of session or something else, but it's blank.
OData is a stateless protocol, meaning the server responds your query, then forgets you were ever there. By definition, this does not allow you to transport main memory content from one request to the next.
User interfaces on the other hand usually require state. It can be gained through one of the following options:
Stateful user interface
As Haojie points out, one solution is to store the data that was selected in the user interface and submit it as a filter criterion back to the server with the next request. Having a stateful user interface is the standard solution for stateless server apps.
Stateful persistence
Another option is to store the data permanently in the server's database, in ABAP preferredly in a business object. This object has a unique identifier, probably a GUID, that you can reference in your requests to identify the process you are working on.
Draft persistence
If not all information is available in one step, such as in a multi-step wizard, should not become "active" right away, or you want to be able to switch devices while working on a multi-step process, drafts are an option. Drafts are regular business objects, with the one specialty that they remain inert until the user triggers a final activation step.
Soft state
For performance optimizations, you can have a look at SAP Gateway's soft state mode, which allows you to buffer some data to be able to respond to related requests more quickly. This is generally discouraged though, as it contradicts the stateless paradigm of OData.
Stateful protocol
In some cases, stateless protocols like OData are not the right way to go. For example, banking apps still prefer to pertain state to avoid that users remain logged in infinitely, and thus becoming vulnerable to attacks like CSRF. If this is the case for you, you should have a look at ABAP WebDynpro for your user interface. Generally, stateful server protocols are considered inferior because they bind lots of server resources for long times and thus cannot handle larger user numbers.
When ther user click on OfferId field, it will start a NEW session and of course what you store as GV_CONTENT in class ZCL_CUAN_CLASS is lost.
What you should do is that for the second request you should send to backend with filter Template_ID so in your CL_CUAN_CAMPAIGN_DPC->GET_OFFER_BY_TEMPLATE() method, you can further process the result by Template_ID.
Or SET/GET Parameter.
Scenario:
(with an ASP.NET web app - Core or MVC)
I have a database with Users and Items for each user.
That means the UserId is a foreign key in the Items table.
From the browser I login as a User. I get my Items as a list of ItemViewModels, which are mapped (AutoMapper) to ItemViewModels via a simple api GET request.
I want to update one of the items (which should belong to me - the logged in user) via a simple API call. So I send the modified item back to the server via a PUT request as an ItemViewModel.
First approach:
The simplest approach would be to include the Item's database ID, ItemId, in the ItemViewModel - so when I receive the item to be updated as an ItemViewModel, I can map it back to the existing item in the database.
This however sounds pretty unsafe to me, as anyone could modify the PUT request with any ItemId and affect items which don't belong to the user who executed the request. Is there anything I'm missing about this approach?
Second approach:
Don't pass the database PK ItemId in the ItemViewModel.
Instead use an additional form of identification: let's say that user X has 10 items. And they are numbered from 1 to 10 using a property named UserItemId(which also exists in the database).
I can then pass this UserItemId in the ItemViewModel and when I get it back I can map it to an existing Item in the database (if all was ok with the request) or discard it and reject the request if the UserItemId didn't match anything from the logged in user's items.
Is anyone using this approach?
Pros:
The user only has access to it's own items and can't affect anyone else's since it doesn't know the actual Item ID (primary key), and any modifications are restricted to it's items.
Cons:
A great deal of extra management must be implemented on the server side for this approach to work.
Any other approaches ?
Please consider that the case mentioned above applies to all entities in the database which a client side implementation can CRUD, so it's not just the simple case described above.
The proposed solution should work for the entire app data.
I know this question has been asked here and here but the first one doesn't have a satisfying answer and I don't think the second one really applies to my situation, since it just deals with the UserId.
Thanks.
EDIT
Please consider the Item above as an aggregate root which contains multiple complex subItems each with a table in the db. And the question applies for them as much as for the main Item. That means that each subItem is passed as a ViewModel to the client.
I should mention that regarding further securing the update request:
For the first approach I can easily check if the user is allowed to change the item. But I should do this for all subItems too.
For the second approach I can check if the user can update the Item as follows: I get the userItemId of the incoming ViewModel -> I get all the logged in user's items from the database and try to find a match with the same userItemId, if I get a hit then I proceed with the update.
I think your application is not secure, if you only hide the Id.
You must check, before changing the database entity, if the user is allowed to change the entity.
In your case you should check, if your Id from the authenticated user is the UserId in your item.
If your ViewModel ist similar or identical for your API you could use a FilterAttribute in your controller.
While there are similar questions here, none gave a complete answer, so I am posting a new one.
I have a paged grid - jqgrid - which receives data from server by ajax, N rows (10, 20 and so on, depending on the user selection) each time. There is a boolean value in the grid row model, which is transformed into a checkbox in the displayed row.
When user checks the checkbox and then navigates to the next grid page, the state of the checkbox is obviously lost. What is the best approach to save it? Neither of the possibilities that I see fully satisfies me:
I can save the ids of the selected instances into a global javascript object on checkbox click. Thus when new dataset is obtained, I can iterate through all received instances looking for already selected ones. However this can mean a lot of javascript operations and possible slowdown for the final user, if there are a lot of selected instances.
I can store the selection on the server (session, database, whatever else). This way each time the model is generated, I will populate its boolean parameter with an adequate value. However, this can mean that when the user navigates away from my page without submitting the changes and then returns back, the record states will be restored. I am not sure whether this is good. Generally, I am strongly against storing anything on the server side before user submits the form.
So, what would you choose / offer?
I am using ASP.NET MVC 2.0, C# 4.0, if that matters.
Your question is essentially about preserving state in an ajax scenario that does not involve the evil webforms viewstate.
However, there is nothing wrong with viewstate when it is used to preserve state in the kind of scenarios you are working on (as opposed to providing a means to pretend a web page is a winform).
So, why not go for the best of both worlds and store the values in an encrypted hidden field, a sort of lean, mean, smart man's viewstate?
When you request the next page of data, pass back to the server the existing "viewstate" (if any) plus the new checked items, decrypt the viewstate on the server, see what is in there and if it is relevant to the next page, add the new list of checked items, encrypt that and send the new "viewstate" back to the user.
I haven't done this, so it is just an idea. However, it is logically feasible, and very practical. I say I haven't done this with a grid, but I have done it, with huge success, to design a wizard framework that works a dream.
My wizards preserve their state whilst the user is filling in the forms and only in the final step does anything get persisted (if at all, depending on what the app requires).
This framework is based on the wizard described in Steve Sanderson's book, but extended to work seamlessly with or without ajax. And with a very simple API for controllers derived from my wizard controller.
The code that makes this viewstate work is called from an OnActionExecuting method:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["wizardData"];
if (serialized != null) // Form was posted containing serialized data
{
WizardData = (TModel)new MvcSerializer().Deserialize(serialized);
}
}
And then in the ViewResult returned to the user:
<%= Html.Serialize("wizardData", Model)%>
In your case, as you are just paging data, you would need to serialize and encrypt the equivalent of the wizardData object and send this back with the JSON data to store somewhere in a hidden field.
This is a bit vague, as a wizard is a not a grid of paged data. But the principles (essentially, roll your own viewstate) do apply to both scenarios.
I have addressed this very situation by writing a list of the 'selected' checkboxes in a hidden div when the next page is selected. That way the client maintains the selection list, and no server interaction is required. In addition, when the user finally submits the page, I simply iterate over all the checkboxes in the visible page and the hidden div.
In my system, even in examples where users select hundreds of items, performance is not an issue.
Here's a simple problem: users want to edit products in grid-like manner: select and click add, select and click add... and they see updated products list... then click "Finish" and order should be saved.
However, each "Add" have to go to server, because it involves server-side validation. Moreover, the validation is inside domain entity (say, Order) - that is, for validation to happen I need to call order.Add(product) and then order decides if it can add the product.
The problem is, if I add products to order, it persists changes so even if users do not click "Finish" the changes will still be there!
OK, I probably shouldn't modify the order until users click Finish. However, how do I validate the product then? This should be done by the order entity - if product is already added, if product does not conflict with other products, etc.
Another problem, is that I have to add product to order and "rebuild view/HTML" based on its new state (as it can greatly change). But if I don't persist order changes, the next Add will start from the same order each time, not from the updated one. That is, I need to track changes to the order somehow.
I see several solutions:
Each time the user click Add, retrieve order from database, and add all new products (from the page), but do not persist it, just return View(order). The problem is I cannot redirect from POST /Edit to GET /Edit - because all the data only exists in the POST data, and GET lose it. This means that Refresh page doesn't work in a nice way (F5 and you get duplicated request, not to mention the browser's dialog box)).
Hm, I thought I can do redirect to GET using TempData (and MvcContrib helper). So after POST to /Edit I process business logic, gets new data for view, and do RedirectToAction<>(data) from MvcContrib that passes data via TempData. But since TempDate is... temp... after F5 all the data is lost. Doesn't work. The damn data should be stored somewhere, this way or another.
Store "edit object" in Session with the POST data (order, new products info). This can also be database. Kind of "current item - per page type". So page will get order ID and currently added products from this storage. But editing from multiple pages is problematic. And I don't like storing temp/current objects in Session.
Marking products as "confirmed" - if we do /order/show, we first cleanup all non-confirmed products from the order. Ugly and messy logic.
Make a copy of the order - a temporary one - and make /Edit work with it. Confirm will move changes from temp order to persisted. A lot of ugly work.
Maybe some AJAX magic? I.e. "Add" button won't reload page but will just send new + already added products to server, server will validate as order.Add(products + newproduct) but will not persist changes, will just return updated order information to re-build the grid. But Refresh/F5 will kill all user-entered info.
What else?
Is this problem common? How do you solve similar ones? What's the best practices?
It depends a lot on how you implement your objects/validation, but your option number 5 is probably the best idea. If AJAX isn't your thing, you can accomplish the same thing by writing the relevant data of already-added-but-not-saved entries to hidden fields.
In other words, the flow ends up something like this:
User enters an item.
Item is sent to the server and validated. The view is returned with the data entered by the user in hidden fields.
User enters a second item.
Item is sent to the server, and both items are validated. The view is returned with the data for both items in hidden fields.
etc.
So far as F5/Refresh killing entered data... In my experience this isn't too much of a problem. A more pressing concern is the back/forward buttons, which need to be managed with something like Really Simple History.
If you DO want to make the page continue to work after a refresh, you need to do one of the following:
Persist the records to the database, associated with the current user in some way.
Persist the records to session.
Persist the records to the query string.
These are the only storage locations available that persist through both redirection and refreshes.
If I were you, I would come up with something which resembles option 5. And since you say that you are comfortable with Ajax you can try this. But before you do this, you should move your validation logic outside the Order.Add() method. Maybe you can move it to another public function called Validate() which returns a bool. And you can still call the same Validate() in the Add() method, thereby doing the necessary validation before you add the order.
Try to do the validation on the client side. If you are using jQuery, you can use the jquery validate plugin. But, if this is not possible for some reason (such as when you need to validate stuff against a database). You should do your validation on the server side and just return a JSON object with the 'success' boolean flag and an optional message, just a way to mark that the data is valid. You would allow the user to add a new product only if the previous Order was valid.
And when the user hits finish send the product to the server and do the validation again, but persist the order in this round-trip.
Now, If I had a complete say in this, I wouldn't even go to the extent of doing validation whenever a product is added/edited. I would just do the validation whenever the customer hits finish. That would be the simplest solution. But, maybe I am missing something.
I am using the Redirect After Post pattern in my ASP.NET MVC application. I have
the following scenario:
User goes to /controller/index where he is asked to fill a form.
Form values are POSTed to /controller/calculate.
The Calculate action performs calculation based on input and instantiates a complex object containing the results of the operation. This object is stored in TempData and user is redirected to /controller/result.
/controller/result retrieves the result from TempData and renders them to the user.
The problem with this approach is that if the user hits F5 while viewing the results in /controller/result the page can no longer be rendered as TempData has been expired and the result object is no longer available.
This behavior is not desired by the users. One possible solution would be instead of redirecting after the POST, just rendering the results view. Now if the user hits F5 he gets a browser dialog asking if he wants to repost the form. This also was not desired.
One possible solution I thought of was to serialize the result object and passing it in the URL before redirecting but AFAIK there are some limitations in the length of a GET request and if the object gets pretty big I might hit this limitation (especially if base64 encoded).
Another possibility would be to use the Session object instead of TempData to persist the results. But before implementing this solution I would like to know if there's a better way of doing it.
UPDATE:
Further investigating the issue I found out that if I re-put the result object in TempData inside the /controller/result action it actually works:
public ActionResult Result()
{
var result = TempData["result"];
TempData["result"] = result;
return View(result);
}
But this feels kind of dirty. Could there be any side effects with this approach (such as switching to out-of-process session providers as currently I use InProc)?
Store it in the Session with some unique key and pass the key as part of the url. Then as long as the session is alive they can use the back/forward button to their heart's content and still have the URL respond properly. Alternatively, you could use the ASP cache, but I'd normally reserve that for objects that are shared among users. Of course, if you used the parameters to the calculation as the key and you found the result in the cache, you could simply re-use it.
I think redirect after post makes much more sense when the resulting Url is meaningfull.
In your case it would mean that all data required for the calculation is in the Url of /controller/result.
/controller/calculate would not do the calculation but /controller/result.
If you can get this done thinks get pretty easy: You hash the values required for the calculation and use it as the key for the cache. If the user refreshes he only hits the cache.
If you cant have a meaningfull url you could post to /controller/index. If the user hits F5 calculation would start again, but a cache with the hash as key would help again.
TempData is generally considered useful for passing messages back to the user not for storing working entities (a user refresh will nuke the contents of TempData).
I don't know of more appropriate place than the session to store this kind of information. I think the general idea is keep session as small as possible though. Personally I usually write some wrappers to add and remove specific objects to session. Cleaning them up manually where possible.
Alternatively you can store in a database in which you purge stale items on a regular basis.
I might adopt a similar idea to a lot of banks on their online banking sites by using one-time keys to verify all POSTs. You can integrate it into a html helper for forms and into your service layer (for example) for verification.
Let's say that you only want to post any instance of a form once. Add a guid to the form. If the form does not post back and the data is committed then you want to invalidate the guid and redirect to the GET action. If say the form was not valid, when the page posts back you need a new (valid) guid there in the form waiting for the next post attempt.
GUIDs are generated as required and added to a table in your DB. As they are invalidated (by POSTS, whether successful or not) they are flagged in the table. You may want to trim the table at 100 rows.. or 1000, depending on how heavy your app will be and how many rendered but not yet posted forms you may have at any one time.
I haven't really fine tuned this design but i think it might work. It wont be as smelly as the TempData and you can still adhere to the PRG pattern.
Remember, with PRG you dont want to send the new data to the GET action in a temp variable of some sort. You want to query it back from the data store, where it's now committed to.
As Michael stated, TempData has a single purpose -> store an object for one trip only and only one trip. As I understand it, TempData is essentially using the same Session object as you might use but it will automatically remove the object from the session on the next trip.
Stick with Session imho rather than push back in to TempData.