跳转至

SQL injection

SQL 注入

描述

SQL 注入是一种漏洞,攻击者将恶意的 SQL 查询注入到输入字段中,从而操纵应用程序 SQL 数据库的行为。通过利用此漏洞,攻击者可以获得对数据库的未经授权的访问,检索、修改或删除敏感数据,或在数据库上执行管理操作。SQL 注入通常是由于未对用户输入进行适当的净化而引起的,这允许攻击者绕过身份验证、执行任意 SQL 命令并利用底层数据库。

示例

  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();
  ?>

建议

为防止 SQL 注入攻击,请考虑以下措施:

  • 参数化查询:使用参数化查询或预处理语句来执行 SQL 查询。参数化允许将 SQL 代码与用户输入分开,从而防止注入攻击。

  • 输入净化:在将用户输入用于 SQL 查询之前,对其进行验证和净化。通过仅允许预期的字符和格式来实施严格的输入验证。

  • 最小特权原则:对数据库用户使用最小特权原则。分配最小的必要权限以限制成功的注入攻击的影响。

  • ORM 和库:利用动态处理 SQL 查询的对象关系映射 (ORM) 库或框架。这些框架通常提供针对注入攻击的内置保护。

示例

  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();
  ?>

链接

标准

  • 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