FlawOpen

flawopen.com/SQL Injection em PHP/mysqli vs PDO

MySQLi vs PDO: prepared statements seguros

Página de referência
Resposta curta

Uma prepared statement mantém as instruções SQL fixas e envia os valores separadamente, como preencher campos identificados em um formulário. PDO e MySQLi fazem isso. A segurança vem do binding correto, não do nome da biblioteca.

A mesma consulta, preparada com qualquer API

INSEGURO — SQL com dados da requisição
$userId = $_GET['id'];
$sql = "SELECT id, email FROM users WHERE id = " . $userId;

// Both calls execute the already-built SQL string:
$rows = $mysqli->query($sql);
$rows = $pdo->query($sql);
SEGURO — vincule valores em ambas APIs
// PDO
$stmt = $pdo->prepare(
    "SELECT id, email FROM users WHERE id = :id"
);
$stmt->execute(["id" => $userId]);

// MySQLi
$stmt = $mysqli->prepare(
    "SELECT id, email FROM users WHERE id = ?"
);
$stmt->bind_param("i", $userId);
$stmt->execute();

Portabilidade de banco é a principal diferença do PDO

Portabilidade de banco é a principal diferença do PDO

PDO oferece uma interface comum para vários drivers; MySQLi é voltado a MySQL e MariaDB. PDO não torna SQL portável automaticamente: dialetos, drivers e recursos ainda variam.

Os estilos de placeholder diferem

PDO aceita placeholders nomeados como :id ou posicionais ?, conforme o driver; não misture os estilos na mesma instrução. MySQLi usa ? posicional. Ambos vinculam valores, mas não nomes de tabela/coluna, palavras-chave ou ordenação.

O modo de preparação do PDO depende do driver

Drivers PDO podem usar prepared statements nativas ou emuladas. No MySQL, PDO::ATTR_EMULATE_PREPARES controla a emulação quando disponível; alguns drivers emulam ou recorrem a ela quando a preparação nativa não é possível. Siga a documentação do driver. Essa opção não protege SQL interpolado: mantenha o texto fixo e vincule valores em qualquer modo.

Regras que evitam SQL injection em ambas as bibliotecas

Use prepare() e vincule cada valor não confiável. Mantenha a sintaxe SQL fixa; selecione identificadores dinâmicos por um mapa estrito no servidor ou use variantes finitas de consulta. Prepared statements não autorizam acesso a registros: restrinja a consulta ao usuário autenticado quando necessário. Em LIKE, binding evita injeção de sintaxe, mas % e _ continuam curingas, a menos que sejam escapados para busca literal.

Escolhendo entre PDO e MySQLi

Perguntas frequentes

Placeholders nomeados do PDO são mais seguros que ? do MySQLi?

Não. Ambos vinculam valores com segurança quando a consulta é preparada e os valores são vinculados. Nomes podem melhorar a leitura; não vinculam identificadores nem substituem autorização.

Devo sempre desativar prepared statements emulados no PDO?

Não como regra universal. Suporte e fallback variam por driver. Consulte a documentação e os requisitos da aplicação. Em qualquer modo, mantenha a estrutura SQL fixa e passe valores como parâmetros.

Um prepared statement pode vincular nome de tabela ou coluna?

Não. Parâmetros representam valores, não identificadores ou palavras-chave SQL. Mapeie escolhas do cliente a um conjunto finito de fragmentos confiáveis no servidor.

Referências

Veja também SQL Injection (CWE-89): como funciona e como evitar em todas as linguagens — flawopen.com NHibernate protege contra SQL Injection? MongoDB NoSQL Injection: filtros de consulta seguros String de IDs numéricos também pode causar SQL Injection? O que é uma consulta parametrizada? Prisma $queryRaw: é seguro contra SQL Injection? Interpolação em where() do Rails é segura?