Pages

14 December, 2020

How can I prevent SQL injection in PHP?

 <?php 





Use prepared statements and parameterized queriesThese are SQL statements that are sent to and parsed by the database server separately from any parametersThis way it is impossible for an attacker to inject malicious SQL.
You basically have two options to achieve this


Using PDO (for any supported database driver):
    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute([ 'name' => $name ]);
    
    foreach ($stmt as $row) {
        // Do something with $row
    }
    Using MySQLi (for MySQL):
    
    $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
    $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
    
    $stmt->execute();
    
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // Do something with $row
    }
    If you're connecting to a database other than MySQL, there is a driver-specific second option that you can refer to (for example, pg_prepare() and pg_execute() for PostgreSQL). PDO is the universal option.
    
    Correctly setting up the connection
    Note that when using PDO to access a MySQL database real prepared statements are not used by default. To fix this you have to disable the emulation of prepared statements. An example of creating a connection using PDO is:


    $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');
    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    In the above example the error mode isn't strictly necessarybut it is advised to add it. This way the script will not stop with a Fatal Error when something goes wrong. And it gives the developer the chance to catch any error(s) which are thrown as PDOExceptions.
    What is mandatoryhoweveris the first setAttribute() linewhich tells PDO to disable emulated prepared statements and use real prepared statementsThis makes sure the statement and the values aren't parsed by PHP before sending it to the MySQL server (giving a possible attacker no chance to inject malicious SQL).
    Although you can set the charset in the options of the constructorit's important to note that 'olderversions of PHP (before 5.3.6) silently ignored the charset parameter in the DSN.
   **- Explanation -**
    The SQL statement you pass to prepare is parsed and compiled by the database serverBy specifying parameters (either a ? or a named parameter like :name in the example aboveyou tell the database engine where you want to filter onThen when you call executethe prepared statement is combined with the parameter values you specify.
    The important thing here is that the parameter values are combined with the compiled statementnot an SQL stringSQL injection works by tricking the script into including malicious strings when it creates SQL to send to the databaseSo by sending the actual SQL separately from the parametersyou limit the risk of ending up with something you didn't intend.
    Any parameters you send when using a prepared statement will just be treated as strings (although the database engine may do some optimization so parameters may end up as numbers tooof course). In the example aboveif the $name variable contains 'Sarah'; DELETE FROM employees the result would simply be a search for the string "'Sarah'; DELETE FROM employees"and you will not end up with an empty table.
    Another benefit of using prepared statements is that if you execute the same statement many times in the same session it will only be parsed and compiled oncegiving you some speed gains.
    Ohand since you asked about how to do it for an inserthere's an example (using PDO):
    $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
    $preparedStatement->execute([ 'column' => $unsafeValue ]);
    
?>

No comments:

Post a Comment

Thanks