Inappropriate coding practices - TypeScript

Inappropriate coding practices - TypeScript

Need

Enforcement of proper encapsulation in coding practices

Context

  • Usage of TypeScript for statically typed JavaScript development
  • Usage of Express for building web applications and APIs

Description

Non compliant code

        import express from 'express';

class User {
  public id: number;
  public name: string;
  public email: string;

  constructor(id: number, name: string, email: string) {
    this.id = id;
    this.name = name;
    this.email = email;
  }
}

const app = express();

app.get('/user/:id', (req, res) => {
  const userId = parseInt(req.params.id);
  const user = new User(userId, 'John Doe', 'johndoe@example.com');
  res.json(user);
});

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

The vulnerability in the given code is that the fields of the User class ( id, name, and email) are defined as public. This violates the encapsulation principle, which states that the internal state of an object should be hidden and accessed only through methods.

By having public fields, anyone can directly access and modify the attributes of a User object. This can lead to unauthorized access and modification of sensitive data. For example, an attacker could modify the id field to gain access to another user's data or change the email field to impersonate another user.

To fix this vulnerability, the attributes of the User class should be set as private. Private attributes can only be accessed and modified within the class itself. To provide controlled access to these attributes, getter and setter methods should be implemented. These methods can enforce any necessary validation or access control logic before allowing access or modification of the attributes.

Steps

  • Change the access modifiers of the fields in the User class from 'public' to 'private'.
  • Generate getter methods for each field in the User class.
  • Update the code in the '/user/:id' route handler to use the getter methods instead of accessing the fields directly.

Compliant code

        import express from 'express';

class User {
  private id: number;
  private name: string;
  private email: string;

  constructor(id: number, name: string, email: string) {
    this.id = id;
    this.name = name;
    this.email = email;
  }

  getId(): number {
    return this.id;
  }

  getName(): string {
    return this.name;
  }

  getEmail(): string {
    return this.email;
  }
}

const app = express();

app.get('/user/:id', (req, res) => {
  const userId = parseInt(req.params.id);
  const user = new User(userId, 'John Doe', 'johndoe@example.com');
  res.json({
    id: user.getId(),
    name: user.getName(),
    email: user.getEmail()
  });
});

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

The fixed code addresses the vulnerability of inappropriate coding practices by implementing proper encapsulation.

In the User class, the fields (id, name, and email) are now declared as private, which means they can only be accessed within the class itself. This ensures that the attributes cannot be obtained or modified directly from outside the class.

To provide controlled access to these private attributes, getter methods (getId, getName, and getEmail) are implemented. These methods allow external code, such as the route handler in this case, to retrieve the values of the private attributes.

In the route handler, when a GET request is made to '/user/:id', the user's id is extracted from the request parameters and used to create a new User object. The getter methods are then used to retrieve the user's id, name, and email, which are sent as a JSON response.

By setting the attributes as private and generating getter methods, the code ensures that the private attributes cannot be accessed or modified directly, adhering to the principle of encapsulation.

References