コンテンツにスキップ

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