logo

Hidden fields manipulation - Typescript


Need

Prevention of unauthorized manipulation of hidden fields


Context

  1. Usage of TypeScript for statically typed JavaScript development
  2. Usage of Express for building web applications and APIs

Description

Insecure Code Example

import express from 'express';

const app = express();
app.use(express.urlencoded({ extended: true }));

app.get('/profile', (req, res) => {
  res.send(`
    <form action="/update-profile" method="POST">
      <input type="hidden" name="isAdmin" value="false">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">
      <button type="submit">Update Profile</button>
    </form>
  `);
});

app.post('/update-profile', (req, res) => {
  const { username, password, isAdmin } = req.body;

  if (isAdmin === 'true') {
    // Perform privileged action
    res.send('Profile updated as admin!');
  } else {
    // Perform regular action
    res.send('Profile updated!');
  }
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

The vulnerability in this code is hidden fields manipulation. In the `/profile` route, a form is rendered with three input fields: `username`, `password`, and `isAdmin`. The `isAdmin` field is hidden from the regular user, meaning it is not visible on the form. When the form is submitted to the `/update-profile` route, the server retrieves the values of `username`, `password`, and `isAdmin` from the request body. The vulnerability lies in the fact that an attacker can manipulate the hidden `isAdmin` field by modifying its value in the request. Since the server blindly trusts the value of `isAdmin` received from the request, an attacker can set `isAdmin` to `'true'` and force the server to perform privileged actions that should only be allowed for administrators. This can lead to unauthorized access, data manipulation, or other undesired behaviors in the application. To fix this vulnerability, the server should not rely on client-provided values for sensitive or privileged actions. Instead, the server should validate and control such values on the server-side to ensure the integrity and security of the application.

Steps

  1. Remove the hidden field 'isAdmin' from the form in the '/profile' route
  2. Validate the 'isAdmin' field on the server-side to ensure it cannot be manipulated by the user
  3. Perform privileged actions only if the 'isAdmin' field is set to 'true' after validation

Secure Code Example

import express from 'express';

const app = express();
app.use(express.urlencoded({ extended: true }));

app.get('/profile', (req, res) => {
  res.send(`
    <form action="/update-profile" method="POST">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">
      <button type="submit">Update Profile</button>
    </form>
  `);
});

app.post('/update-profile', (req, res) => {
  const { username, password } = req.body;
  const isAdmin = false; // Set isAdmin to false by default

  if (req.user.isAdmin === true) {
    isAdmin = true; // Validate the isAdmin field on the server-side
  }

  if (isAdmin) {
    // Perform privileged action
    res.send('Profile updated as admin!');
  } else {
    // Perform regular action
    res.send('Profile updated!');
  }
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

The fixed code addresses the vulnerability by implementing server-side validation and only sending the fields that require user input in the requests. 1. The code uses the Express framework to create a server. 2. The `express.urlencoded()` middleware is used to parse the request body and make it accessible in the `req.body` object. 3. The `/profile` route handles the GET request and renders a form with two input fields: `username` and `password`. 4. The form's `action` attribute is set to `/update-profile` and the `method` attribute is set to POST. 5. The `/update-profile` route handles the POST request and retrieves the `username` and `password` values from the `req.body` object. 6. The code introduces a variable `isAdmin` and sets it to `false` by default. 7. It then checks if `req.user.isAdmin` is `true` to validate the `isAdmin` field on the server-side. This ensures that only authorized users can set `isAdmin` to `true`. 8. If `isAdmin` is `true`, it performs a privileged action and sends a response indicating that the profile has been updated as an admin. 9. If `isAdmin` is `false`, it performs a regular action and sends a response indicating that the profile has been updated. 10. The server listens on port 3000 for incoming requests. By validating the `isAdmin` field on the server-side and only sending the necessary fields in the request, the code mitigates the risk of hidden field manipulation vulnerability.


References

  • 093 - Hidden fields manipulation

  • Last updated

    2023/09/18