Impedir injeção de SQL em PHP

Subodh Poudel 30 janeiro 2023
  1. Use as instruções preparadas e o PDO para evitar injeção de SQL em PHP
  2. Use as instruções Prepared com a consulta parametrizada para evitar injeção de SQL em PHP
  3. Defina o atributo PDO::ATTR_EMULATE_PREPARES como false para evitar a injeção de SQL
Impedir injeção de SQL em PHP

Apresentaremos um método para prevenir a injeção de SQL em PHP usando as instruções preparadas e o PHP Data Objects (PDO). Usamos PDO para estabelecer a comunicação do banco de dados neste método. Este método envia os dados e a consulta separadamente para o servidor de banco de dados, o que evita a mistura dos dados e do servidor.

Apresentaremos um método para prevenir a injeção de SQL em PHP usando as instruções preparadas e a consulta parametrizada. Usamos mysqli para estabelecer a comunicação do banco de dados neste método. Este método possui um mecanismo de funcionamento semelhante ao primeiro método. O ponto de contraste são apenas as funções mysqli que usamos para prevenir a injeção de SQL.

Mostraremos um exemplo de como se proteger da injeção de SQL ao usar o PDO no PHP, definindo a emulação de instruções preparadas como false.

Use as instruções preparadas e o PDO para evitar injeção de SQL em PHP

Podemos usar a instrução preparada junto com o PDO para evitar injeção de SQL no PHP. A injeção de SQL ocorre quando há a mistura da consulta e dos dados durante o envio ao banco de dados. Neste método, não especificamos o valor exato dos dados na instrução SQL. Em vez disso, usamos os marcadores de posição. Devido a isso, as instruções SQL parametrizadas são enviadas ao servidor como a primeira solicitação. Usamos a função prepare() para fazer isso. Vinculamos o valor exato do parâmetro na segunda solicitação ao servidor de banco de dados. Usamos a função bindValue() para este propósito. Assim, enviamos o programa na primeira solicitação e os dados na segunda solicitação. Se solicitarmos os dados junto com os códigos SQL, o usuário pode alterar o programa e escrever códigos maliciosos. Assim, evita que códigos SQL maliciosos sejam injetados no servidor.

Por exemplo, uma tabela usuários contém os seguintes campos e dados.

+----+-----------+----------+------------+
| id | firstname | lastname | dob        |
+----+-----------+----------+------------+
|  1 | bruce     |  rose    | 1998-02-13 |
|  2 | jeff      |  james   | 2000-03-30 |
+----+-----------+----------+------------+

Ele cria uma variável $firstname e atribui a ela o nome bruce. Ele cria uma variável $sql e escreve uma consulta SELECT * FROM users WHERE firstname =:fname; nele.

Não escreva o valor exato dos dados para firstname. Em vez disso, use o parâmetro :fname. Use a variável $pdo para chamar a função prepare() na variável de consulta. Substitua o valor de :fname pela variável $firstname. Execute a instrução com a função execute(). Verifique o resultado com a função fetch() se as credenciais correspondem ao banco de dados. Em caso afirmativo, exiba o id, firstname e o lastname da linha selecionada.

O exemplo abaixo demonstra o uso de uma declaração preparada. Ele armazena o valor do campo firstname em uma variável para verificar se a credencial corresponde. Se a variável contiver algum código malicioso, ela exibirá a mensagem Credentials do no match. Isso ocorre porque a função prepared() leva apenas a consulta parametrizada e não permite os dados exatos. A variável $pdo contém o objeto da conexão do banco de dados.

Código de exemplo:

# php 7.*
<?php
$firstname = "bruce";
$sql = "SELECT * FROM users WHERE firstname =:fname ;";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":fname", $firstname);
$stmt->execute();
if(!$result = $stmt->fetch(PDO::FETCH_OBJ)){
    echo "Credentials do no match";
} else {
    echo"Id: ".$result->id. " Name: ".$result->firstname." ".$result->lastname;
}
?>

Resultado:

Id: 1 Name: bruce rose

Use as instruções Prepared com a consulta parametrizada para evitar injeção de SQL em PHP

Podemos usar a instrução preparada junto com a consulta parametrizada para evitar injeção de SQL no PHP. Usamos o objeto da função mysqli() para criar uma conexão de banco de dados. Neste método, usamos um símbolo de ponto de interrogação ? como marcadores de posição dos dados. Usamos a função prepare() como o método acima. Usamos a função bind_param() para vincular os dados reais no placeholder. Este método segue um mecanismo de trabalho semelhante ao método acima.

Por exemplo, estabeleça uma conexão de banco de dados criando um objeto da função mysqli() e atribua-o a uma variável $conn. Atribua com o nome jeff a uma variável $firstname. Crie uma variável $sql e escreva uma consulta SELECT * FROM users WHERE first name =?;. Use a variável $conn para chamar a função prepare() na variável de consulta. Substitua o marcador ? com a variável $firstname. Execute a instrução com a função execute(). Chame a função get_result() para armazenar o resultado na variável $result. Verifique se a linha existe com a propriedade num_rows e retorne a mensagem No Rows com a função exit() se a condição falhar. Chame o método fetch_assoc() e armazene-o na variável $row em um loop while. Exibe o id, firstname e o lastname da linha selecionada.

Código de exemplo:

#php 7.x
<?php
$conn = new mysqli($host, $user, $pwd, $dbName);
$firstname = "jeff";
$sql = "SELECT * FROM users WHERE firstname = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $firstname);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) exit('No rows');
    while($row = $result->fetch_assoc()) {
    echo"Id: ".$row['id']. " Name: ".$row['firstname']." ".$row['lastname'];
}

Resultado:

Id: 2 Name: jeff james

Defina o atributo PDO::ATTR_EMULATE_PREPARES como false para evitar a injeção de SQL

Usar instruções preparadas no PDO pode não ser suficiente para evitar a injeção de SQL se não definirmos os atributos do PDO corretamente. Devemos definir o atributo PDO::ATTR_EMULATE_PREPARES para false para evitar a injeção. Se definirmos o atributo como true, o PDO apenas emulará as instruções preparadas em vez de usá-las. Assim, o sistema ficará vulnerável à injeção de SQL.

Por exemplo, crie uma conexão PDO com o banco de dados em uma variável $pdo. Use a variável para chamar a função setAttribute(). Defina o atributo PDO::ATTR_EMULATE_PREPARES como falso.

Exemplo de código:

#php 7.x
<?php
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
?>
Subodh Poudel avatar Subodh Poudel avatar

Subodh is a proactive software engineer, specialized in fintech industry and a writer who loves to express his software development learnings and set of skills through blogs and articles.

LinkedIn