To give some context on what I know. I learn some time ago from this tutorial even when you set a field from your model READ ONLY on the View how easy is use tools like fiddler to alter the POST data and change the value.
What you do in this case is use Model Binding to specify the list of fields you want Edit and ignore the rest
[HttpPost]
[ActionName("Edit")]
public ActionResult Edit_Post(int id)
{
EmployeeBusinessLayer employeeBusinessLayer = new EmployeeBusinessLayer();
Employee employee = employeeBusinessLayer.Employees.Single(x => x.ID == id);
UpdateModel(employee, new string[] { "ID", "Gender", "City", "DateOfBirth" });
^^^ Name isnt updated
if (ModelState.IsValid)
{
employeeBusinessLayer.SaveEmployee(employee);
return RedirectToAction("Index");
}
return View(employee);
}
Now I learn about Authentication using AspNet.Identity.
Can check if user isn't authenticated to send him to the Login page.
If user belong to certain Role, I can show personalized menus.
Or check the list of contacts for the user and show only those.
But even if you filter the list of contacts based on the user_id before create the view you can access the actions EDIT and DELETE using links like this.
http://MVCDemo/Employee/Edit/1
http://MVCDemo/Employee/Delete/1
And as long you are authenticated, you can change other users data.
So, how you integrate authentication with CRUD actions to avoid unintended actions?
Seem to me to solve this situation I have to apply something similar to the Model Binding example. When get and Edit or Delete post request, first get the Employee from the DB using the id and compare if belong to the current user.
But that create a lot of repeats code across all the functions.
So what is the right way to handle this?
EDIT
To try to make it clear. Lets assume I have an address book application. Each user have contacts:
contact_id user_id name phone ....
1 1 A
2 1 B
3 1 C
4 2 D
5 2 E
6 2 F
The action to show contacts use authenticated user_id to filter the contacts before send it to the view.
Then you have an Edit/Delete actions where you get contact_id and process to Update/Delete. Even when both users have permission to these actions they shouldn't be able to affect other users contacts. But as I explain is very easy change the page using a tool like fiddler.
I can only speak from personal experience but I don't know any MVC features for managing this for you; I've only ever taken the approach you outline of retrieving the data model from the database and explicitly writing the logic to check if the current user has permissions to modify this resource, returning a 401 error if not.
You can compare the incoming request userid with the userid you have in the session, encrypted cookie or web tokens like jwt which ever you use.
Usually if i have load balancer i use encrypted cookie where i store the logged in user's id and compare it with the id i am getting from the request. if both match, update/delete profile else return Unauthorized.
Same can be done in case of Session or tokens as well.
Related
Hi I’m learning Blazor and I’m creating a backend & frontend app ( Blazor web assembly)
It works well, but my question is related to security.
I have user, business customer, and invoice. It's a very simple app
And user Id is a GUID and the others (business customer and invoice) are int & sequential (increment by 1 like 1,2, 3 and …)
Each user can not see the other user’s data and must not has access to them
this app has 2 parts, an API backend, and a Blazor frontend.
lets add some data like :
And End users can use the API only too without using frontend
I have in Invoice Repository:
Task<Invoice> GetInvoicesListAsync(int businessId);
and after verification users can access its invoices List
if we have a verified enduser like “Alex” (in the second row pf user table), can be retrieve the data that its not belong to him
Because BusinessId is sequential and when he knows his business Id is 99 , he can retrieve invoices for business 100,101,102 and … just with some trying
like :
var lst = await GetInvoicesListAsync(101);
my questions are:
1- How we can stop that? Do I need to enforce enduser to enter UserId as well for security into the API params like this :
Task<Invoice> GetInvoicesListAsync(Guid userId, int businessId);
2- If I add userId then is that has impact on the performance? because in this case I need to do Inner join with user table too and if we have complex database then it has big impact on the performance
3- what is your advice
thanks
Answers as point list:
No, you don't. The method GetInvoicesListAsync(int businessId) is good enough from a security point of view. You need to extract the list of business per user and check if the requested business is in the list, or more simply add a where / join condition filtering the invoices on the businesses of the user.
inner join is not a problem if you have the right indexes. Use your DB explain query plan to verify that your query is using index and do not execute any full table scan
when your user call the API you need to verify the user (valid token or cookie) and to obtain teh list of the business associated, so you don't need to receive this info from the API parameters. This is the biggest concern from a security point of view. The rule for secure API is "hey API, what's my name?"
I am developing as asp.net MVC application and I have two routes first is
http://localhost:60184/Owner/Edit/11 which belongs to user-1 and the second is http://localhost:60184/Owner/Edit/1 to user-2. I want both users to edit, delete, update only his/her own data and for that I have use [Authorize(Roles = "Owner")] but both owners can see each other data by only changing the id value in the route?
Any one please help how to solve this?
You just need to add OwnerId field to your database table that you want to edit and compare it with the current user ID.
public ActionResult Edit(SomeVmClass model)
{
var entity = //fetch the entity from DB
if(User.Identity.GetUserId() != entity.OwnerId)
return HttpNotFound();
// your code
}
Any walkthrough / sample code for ASP.Net (MVC Model) reflecting the way to record the current user's id in a table, and later on accessing only reflecting the said data?
For example a simple model for a SQL table recording sales being made by more than 1 selling officer at the same time, with fields like:
SalesDate
SalesAmount
SalesLocation
SalesOfficer (Automatically recording the user's id or relevant data)
Thus, the fourth field in the sample model above recording the user's id in the background so as to retrieve the same relevant data, when either logged-in by the same user or the administrator next time.
Hopefully, the question is simple and clear enough.
Looking forward for your expert advice, guidance and references in this regard.
Thanks in advance.
First of all what you can do is get data of SalesDate,
SalesAmount , SalesLocation in a model from a view. Now you need to know the Id of current logged in user.if you are using Default authentication in mvc you can get the currently logged in user by:
string id=System.Web.HttpContext.Current.User.Identity.GetUserId();
if not use appropriate method to get currently logged in user. After that you can add all the records in your database in your ActionMethod.
[HttpPost]
public ActionResult Create(SalesModel model)
{
tblSales sales=new tblSales();
sales.SalesDate=model.SalesDate;
sales.SalesAmount =model.SalesAmount;
sales.SalesLocation =model.SalesLocation;
sales.SalesOfficer =id; //This is the id of currently logged in user
_db.tblSales.Add(sales);
}
I'm not even sure how to search for this question, so forgive me if I'm asking a duplicate question and would be grateful for any redirection needed.
I have data (Account Number, Password, Internal Y/N) that is being submitted to an Account Table from Navision. I want to use this data to automatically create a user in the UserProfile table (Username = Account Number, Password = Password) and assign that user to the Admin role if Internal = Y and DealerAdmin if Internal = N.
The data will continue to be maintained for Account numbers in Navision, but the DealerAdmin can add additional users from the website. Is this possible? If so, please provide any pointers to tutorials as to where to start? I presume it's a simple SQL statement. Where do I add this code in MVC so that it gets updated every time there's new data in the Account Table?
If you are using SQL why not use a trigger to create a new record in your User UserProfile when your conditions are met?
If this does not work for you can take a look at the post below and call your proc to move the data over if needed.
ASP.NET MVC 4 intercept all incoming requests
I have two views and two controllers. One for clients and the other for their addresses. Clients can have one address. In my model definition for client I allow the addressID of the client to be nullable. When I want to create an address for a client, according to the addressId being null or not i will redirect to either the address's "create" or "details" view. For now I want to just display the clients name when I reach the Create view("creating address for John Doe"). How do i go about doing this? I'm trying to learn MVC slowly and I'm having trouble dealing with the separation of concerns and where to pass data.
Since you are redirecting manually you know the next request for sure. In this case TempData may fit your needs best. If you need the data for more than the next request you should probably use Session or Cookies as already suggested.
Use this to store data for the next request:
TempData["ClientName"] = "John Doe";
And this to get the data out in the next request:
var clientName = TempData["ClientName"];
Please note that TempData stores its data only for the next request. For further info about TempData MSDN is your friend: http://msdn.microsoft.com/en-us/library/dd394711%28v=vs.100%29.aspx
Try to put some code for others to help you better, but for now what I can tell you is that you want to keep state across requests, therefore you have many options. You can keep a session state, you can have a querystring appended to your following requests, you can have cookies transporting the id, etc.
I would recommend you using session for this .. store the username is session("username") and use it in view or in any controller u want ..