We have to secure our Web Application to each and every function. We should not depend on any single function, or we should not leave any one function without validating. If authentication and authorization is required then we have to validate in each and every function.
Generally developers hide or disable the input controls from UI and they don't check in applications, so hackers can use the development tool or any other technique to show or enable the form controls to perform any bad operations.
If any page or data is based on user access, then we have to use authorization for the page or data. Suppose in a company, an employee can see only his pay slip and the HR manager can see each and everyone's pay slip. In this case, if we are validating through UI only and not using an authorization in our business layer or service side, any employee can use his login credentials and after doing some manipulation (showing control, using development tool, using Fiddler etc.) in the UI side, he would be able to get the data through different techniques, if it is not secure in the Server side.
In one of the Applications, the link given below is available only for admin access.
http://localhost:1001/index.html#/admin
In the Server side, if we are checking only the authentication, then maybe any user can copy and paste the URL given above and be able to see the admin screen after giving his own credentials. Therefore, we have to use the authentication and authorization here.
In the Server side, if we are checking only the authentication, then any user can copy and paste the URL given above and will be able to see the admin screen after giving his own credentials. Hence, we have to use the authentication and authorization here.
Let's say we have a sample Application where we are using Web API to authorize a valid user, using an "Authorize" keyword to assign the role based security, given below:
- [Authorize(Roles = "APPROVER")]
- [HttpPost]
- public resultDTO PoApproveReject(PoApproveRejectDTOpoApproveReject)
- {
- ShoppingCart obj = new ShoppingCart();
- return obj.PoApproveReject(poApproveReject);
- }
- [Authorize(Roles = "ADMIN")]
- [HttpGet]
- public List < UserDTO > GetAllUserList()
- {
- ShoppingCart obj = new ShoppingCart();
- return obj.GetAllUserList();
- }
Let's take an example. Suppose in one application "Admin" can update or delete any user but he/she can’t delete himself/herself. Hence, the developer is hiding the "Delete" button, as shown below:
If we are using the steps given above and not validating the Server side then anybody can use the Inspect element and change the control's visibility or can enabl it, as given below:
Therefore, he/she can be able to delete himself/herself, so we have to restrict the UI side as well as the Server side.
The code given below is to validate at Server side.
- if(deleteUser.userId == deleteUser.deleteUserId)
- {
- resultDTO resultDto = new resultDTO();
- resultDto.result = "User cannot Delete himself / herself";
- resultDto.resultWeb = "User cannot Delete himself / herself";
- resultDto.status = 0;
- return resultDto;
- }
In another example, suppose we are to get the user data based on the user ID and we are sending the user ID to the UI when login is successful, and even though in every request we are validating the authentication and authorization and based on the user ID which we are getting back from the UI, we are fetching all the records of the user based on the user ID. In such a scenario, a user can change his user ID, using a different technique, as given below in the screenshot, and he/she is able to get data of other users.
Hence, we have to prevent such unauthorized access, using two way validation -- one is at the client side and the second is at the Server side validation.
In the code snippet, given below, I have used a claim identity and OWIN feature in Web API for the security before further processing.
- if (ValidateUser(deleteUser.deleteUserId))
- {
- ShoppingCart obj = new ShoppingCart();
- return obj.DeleteUser(deleteUser);
- }
- else
- {
- resultDTO resultDto = new resultDTO();
- resultDto.result = "User is not valid";
- resultDto.resultWeb = "User is not valid";
- resultDto.status = 0;
- return resultDto;
- }
- public bool ValidateUser(int Id)
- {
- var identity = (ClaimsIdentity) User.Identity;
- IEnumerable < Claim > claims = identity.Claims;
- int userId = Convert.ToInt32(claims.FirstOrDefault(u => u.Type == "userId")
- .Value);
- if (userId == Id)
- return true;
- else
- return false;
- }
After applying the client side and Server side validation, if any user will change user ID using Fiddler or any other technique, the Application will not allow further processing. Instead, the Application will throw a warning message.
Summary
- Proper authentication and authorization is done by both UI and Service side.
- Never depend on the UI side for any kind of validation.
- Don’t do any hard coding to test. If we are doin it for some special case then make sure to remove all hard code while deploying in production.