Recently I did security and pen-testing assessment of a web application written entirely in PHP, and some of the biggest issues Iāve come along were in-code vulnerabilities to š SQL injections.
To fix this, I recommended using prepared statements and parameterized queries which are basically SQL statements that are sent to and parsed by the database server separately from any parameters. This way it is impossible for an attacker to inject malicious SQL.
You basically have two options to achieve this:
Connect to database with PDO in PHP
Iād recommend usingĀ PDOĀ (PHP Data Objects) to run parameterized SQL queries as not only does this protect against SQL injection, but it also speeds up queries.
And by using PDO rather thanĀ mysql_,Ā mysqli_, andĀ pgsql_Ā functions, you make your application a little more abstracted from the database, in the rare occurrence that you have to switch database providers.
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute([ 'name' => $name ]);
foreach ($stmt as $row) {
// Do something with $row
}
Using MySQLi
$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.
PDO with Prepared Statements
When usingĀ PDOĀ to access a MySQL databaseĀ 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 necessary,Ā but 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Ā mandatory, however, is the firstĀ setAttribute()Ā line, which tells PDO to disable emulated prepared statements and useĀ realĀ prepared statements. This 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 constructor, itās important to note that āolderā versions of PHP (before 5.3.6)Ā silently ignored the charset parameterĀ in the DSN.
BONUS: SQL Injection Cheat Sheet

The SQL Injection Cheat Sheet published by Ferruh Mavituna is a great resource that will allow you to get the basic idea of a potential attack and almost every section includes brief information about itself.



