Injection

Top 10 OWASP


What?

Injection occurs when untrusted data is sent to an interpreter as part of a command or query. Attackers can trick the interpreter into executing unintended commands or accessing unauthorized data. Common types include SQL injection, NoSQL injection, OS command injection, and LDAP injection.

How to Prevent

  • Use a safe API that avoids using the interpreter entirely
  • Use positive server-side input validation
  • Escape special characters using the specific syntax for that interpreter
  • Use LIMIT and other SQL controls within queries to prevent mass disclosure of records in case of SQL injection
  • Use parameterized queries or prepared statements instead of building dynamic queries
  • Use ORMs (Object Relational Mapping) tools
  • Validate and sanitize all client-side input
  • Run your application with minimal privileges to limit the impact of injection attacks
// BAD EXAMPLE - Vulnerable to SQL Injection
app.post("/login", (req, res) => {
  const { username, password } = req.body;
  const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
  db.query(query); // DON'T DO THIS!
});

// GOOD EXAMPLE - Using Parameterized Queries
class UserService {
  static async authenticateUser(username, password) {
    // Using prepared statements with parameters
    const query =
      "SELECT * FROM users WHERE username = ? AND password_hash = ?";
    const hashedPassword = await bcrypt.hash(password, 10);

    try {
      const [user] = await db.query(query, [username, hashedPassword]);
      return user;
    } catch (error) {
      throw new Error("Authentication failed");
    }
  }

  static async createUser(userData) {
    // Using an ORM (Sequelize example)
    const user = await User.create({
      username: userData.username,
      email: userData.email,
      // Other validated fields...
    });

    return user;
  }
}

// Example of Command Injection Prevention
class SystemService {
  static async executeCommand(command, args) {
    // Use spawn instead of exec to avoid shell injection
    const { spawn } = require("child_process");

    // Whitelist allowed commands
    const allowedCommands = ["git", "npm", "node"];
    if (!allowedCommands.includes(command)) {
      throw new Error("Command not allowed");
    }

    // Validate arguments
    const sanitizedArgs = args.map((arg) => {
      // Remove dangerous characters
      return arg.replace(/[;&|`$()]/g, "");
    });

    return new Promise((resolve, reject) => {
      const process = spawn(command, sanitizedArgs, {
        shell: false, // Prevent shell injection
      });

      let output = "";

      process.stdout.on("data", (data) => {
        output += data;
      });

      process.on("close", (code) => {
        if (code === 0) {
          resolve(output);
        } else {
          reject(new Error(`Command failed with code ${code}`));
        }
      });
    });
  }
}