Saltar a contenido

SQL injection

Inyección SQL

Descripción

La inyección SQL es una vulnerabilidad en la que los atacantes inyectan consultas SQL maliciosas en los campos de entrada, manipulando el comportamiento de la base de datos SQL de la aplicación. Al aprovechar esta vulnerabilidad, los atacantes pueden obtener acceso no autorizado a la base de datos, recuperar, modificar o eliminar datos sensibles, o ejecutar operaciones administrativas en la base de datos. La inyección SQL suele surgir debido a una desinfección inadecuada de las entradas del usuario, lo que permite a los atacantes eludir la autenticación, ejecutar comandos SQL arbitrarios y explotar la base de datos subyacente.

Ejemplos

  import java.sql.*;

  public class SQLInjectionDemo {
      public static void main(String[] args) {
          try {
              // Vulnerable Java code prone to SQL Injection
              Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database", "username", "password");
              Statement stmt = conn.createStatement();

              // Vulnerable SQL query without sanitization
              String username = args[0];
              String password = args[1];
              String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
              ResultSet rs = stmt.executeQuery(sql);

              if (rs.next()) {
                  // User authenticated
              } else {
                  // Invalid credentials
              }
              conn.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }
  const mysql = require('mysql');

  // Vulnerable Node.js code prone to SQL Injection
  const connection = mysql.createConnection({
      host: 'localhost',
      user: 'username',
      password: 'password',
      database: 'database'
  });

  // Vulnerable SQL query without sanitization
  const username = req.body.username;
  const password = req.body.password;
  const sql = `SELECT * FROM users WHERE username='${username}' AND password='${password}'`;

  connection.query(sql, (error, results) => {
      if (error) throw error;

      if (results.length > 0) {
          // User authenticated
      } else {
          // Invalid credentials
      }
  });

  connection.end();
  <?php
  // Vulnerable PHP code prone to SQL Injection
  $conn = new mysqli('localhost', 'username', 'password', 'database');
  if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
  }

  // Vulnerable SQL query without sanitization
  $username = $_POST['username'];
  $password = $_POST['password'];
  $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
  $result = $conn->query($sql);
  if ($result->num_rows > 0) {
      // User authenticated
  } else {
      // Invalid credentials
  }
  $conn->close();
  ?>

Recomendación

Para prevenir ataques de inyección SQL, considere las siguientes medidas:

  • Consultas Parametrizadas: Utilice consultas parametrizadas o declaraciones preparadas para ejecutar consultas SQL. La parametrización permite separar el código SQL de la entrada del usuario, previniendo ataques de inyección.

  • Desinfección de Entradas: Valide y desinfecte las entradas del usuario antes de utilizarlas en consultas SQL. Implemente una validación de entrada estricta permitiendo solo los caracteres y formatos esperados.

  • Principio de Menor Privilegio: Utilice el principio de menor privilegio para los usuarios de la base de datos. Asigne los permisos mínimos necesarios para limitar el impacto de ataques de inyección exitosos.

  • ORMs y Bibliotecas: Utilice bibliotecas o frameworks de Mapeo Objeto-Relacional (ORM) que manejen consultas SQL de forma dinámica. Estos frameworks a menudo proporcionan protecciones integradas contra ataques de inyección.

Ejemplos

  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;

  public class ParametrizedQueryExample {
      public static void main(String[] args) {
          String username = "userInput"; // User input
          String password = "userInput"; // User input

          try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "username", "password")) {
              String query = "SELECT * FROM users WHERE username = ? AND password = ?";
              PreparedStatement statement = connection.prepareStatement(query);

              statement.setString(1, username);
              statement.setString(2, password);

              ResultSet resultSet = statement.executeQuery();
              while (resultSet.next()) {
                  // Process the results
              }
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
  const mysql = require('mysql2/promise');

  async function fetchUser(username, password) {
      const connection = await mysql.createConnection({
          host: 'localhost',
          user: 'username',
          password: 'password',
          database: 'db'
      });

      const [rows] = await connection.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);
      connection.end();
      return rows;
  }

  // Usage
  fetchUser('userInput', 'userInput')
      .then(rows => {
          // Process the results
      })
      .catch(err => {
          console.error(err);
      });
  <?php
      $username = $_POST['username'];
      $password = $_POST['password'];

      $db = new mysqli('localhost', 'username', 'password', 'dbname');

      if ($stmt = $db->prepare("SELECT * FROM users WHERE username = ? AND password = ?")) {
          $stmt->bind_param('ss', $username, $password);
          $stmt->execute();

          $result = $stmt->get_result();

          while ($row = $result->fetch_assoc()) {
              // Process the results
          }

          $stmt->close();
      }

      $db->close();
  ?>

Enlaces

Estándares

  • CWE_TOP_25:
    • CWE_89
  • OWASP_ASVS_L1:
    • V5_3_5
  • OWASP_ASVS_L2:
    • V5_3_5
  • OWASP_ASVS_L3:
    • V5_3_5
  • PCI_STANDARDS:
    • REQ_2_2
    • REQ_3_5
    • REQ_4_2
    • REQ_6_2
    • REQ_6_3
    • REQ_6_4
    • REQ_11_3
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_3_4
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213
    • SECURITY255