Skip to main content

Restricted fields manipulation

Need

Prevention of unauthorized access and manipulation of restricted fields

Context

  • Usage of C# 7.1 for modern language features and enhancements
  • Usage of Microsoft.AspNetCore.Mvc for building web applications using the ASP.NET Core MVC framework
  • Usage of Microsoft.EntityFrameworkCore for data access and persistence in .NET applications

Description

Non compliant code

[HttpPost]
public async Task<IActionResult> RegisterEmployee(Employee employee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var existingEmployee = await _context.Employees.SingleOrDefaultAsync(e => e.DNI == employee.DNI);
if (existingEmployee != null)
{
existingEmployee.Name = employee.Name;
existingEmployee.Email = employee.Email;
existingEmployee.DateOfBirth = employee.DateOfBirth;
existingEmployee.Address = employee.Address;
existingEmployee.TelephoneNumber = employee.TelephoneNumber;
await _context.SaveChangesAsync();
}
else
{
_context.Employees.Add(employee);
await _context.SaveChangesAsync();
}

return Ok();
}

In the above code, the RegisterEmployee method in the controller is vulnerable to restricted fields manipulation. This is because it checks if an employee with the provided DNI (Identity Document Number) exists in the database, and if it does, it updates all the employee's information with the new data provided in the request.

This means that an attacker could potentially send a request with an existing DNI but with other fields manipulated, such as the name, email, date of birth, address, and telephone number. The application would then update the existing employee's information with this manipulated data, effectively allowing the attacker to change the information of any employee as long as they know their DNI.

This vulnerability is particularly dangerous because it allows for unauthorized access and manipulation of sensitive data, which could lead to a variety of potential issues including identity theft, unauthorized actions being taken on behalf of the affected employee, and potential legal issues for the company.

Steps

  • Implement authentication and authorization to ensure that only authorized users can access the self-management functionality.
  • Validate the user's permissions before allowing them to modify employee information.
  • Ensure that the employee being modified belongs to the same company as the authenticated user.
  • Use a separate endpoint or form for updating employee information to prevent unauthorized access.
  • Implement input validation to ensure that only valid and expected values can be submitted for employee information.
  • Consider implementing a two-step verification process for confirming employee registrations to prevent unauthorized changes.

Compliant code

[HttpPost]
[Authorize]
public async Task<IActionResult> RegisterEmployee(Employee employee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var currentUser = await _userManager.GetUserAsync(User);
if (currentUser.CompanyId != employee.CompanyId)
{
return Unauthorized();
}

var existingEmployee = await _context.Employees
.Where(e => e.CompanyId == currentUser.CompanyId)
.SingleOrDefaultAsync(e => e.DNI == employee.DNI);

if (existingEmployee != null)
{
existingEmployee.Name = employee.Name;
existingEmployee.Email = employee.Email;
existingEmployee.DateOfBirth = employee.DateOfBirth;
existingEmployee.Address = employee.Address;
existingEmployee.TelephoneNumber = employee.TelephoneNumber;
await _context.SaveChangesAsync();
}
else
{
_context.Employees.Add(employee);
await _context.SaveChangesAsync();
}

return Ok();
}

The updated code now includes an [Authorize] attribute on the RegisterEmployee method. This ensures that only authenticated users can access this endpoint.

We also retrieve the current user's information using _userManager.GetUserAsync(User). This allows us to check if the current user's CompanyId matches the CompanyId of the employee they are trying to modify. If they do not match, we return an Unauthorized response.

When looking for an existing employee, we now also check that the employee belongs to the same company as the current user. This prevents users from modifying employees from other companies.

The rest of the code remains the same. If an existing employee is found, their information is updated. If no existing employee is found, a new one is added. In both cases, the changes are saved to the database.

This code ensures that only authorized users can modify employee information, and only for employees that belong to the same company as them. This prevents unauthorized access and manipulation of employee data.

References