TransWikia.com

Por que dizem que o $_GET no PHP é inseguro contra sql injection?

Stack Overflow em Português Asked by Gonçalo on October 21, 2020

Bom, a minha dúvida, é simples.

Tenho andado ultimamente, a ouvir muitas histórias a dizer que o $_GET no PHP é inseguro contra sql injection.

Poderiam-me dizer porquê?

Obrigado.

One Answer

Não é o $_GET que é inseguro, o problema é como usa ele. Os dados podem vir por $_GET, $_POST, $_COOKIE ou até uma string gravada previamente em um arquivo e posteriormente adicionada a execução de uma query.

O problema está em como passar diretamente os valores na query, por exemplo:

SELECT * FROM tabela WHERE nome LIKE '%{$_GET['nome']}%'

Desta forma seria possível fazer algo como http://site/pagina.php?nome=';QUERY e geraria isto:

SELECT * FROM tabela WHERE nome LIKE '';QUERY'

Claro que no caso acima no máximo obteria uma falha de sintaxe, no geral a API não permite múltiplas queries, agora imagine que os dados de uma SELECT são baseados em um id salvo na sessão e os produtos que o usuário pode visualizar em um painel são somente os com a ID (id_dono) dele:

SELECT * FROM produtos WHERE id_produto={$_GET['idproduto']} AND id_dono={$_SESSION['idautenticado']}

Mas se digitar isso acessar isto http://site/pagina.php?idproduto=6 -- e geraria isto:

SELECT * FROM produtos WHERE id_produto=6 -- OR id_dono=5

Desta maneira o usuário ignorou tudo que vier depois de -- e pode obter os dados privados de produtos de outros usuários em um suposto painel aonde controlaria os seus produtos.

Outro exemplo seria manipular qualquer coluna de uma tabela:

UPDATE dados SET nome='%{$_GET['nome']}%' WHERE id={$_GET['id']}

Suponhamos que temos colunas que não deveria poder ser alteradas, mas se você fizer algo como http://site/pagina.php?id=1&nome=',outracoluna='xxxxxx você irá ter controle sobre qualquer coluna da tabela, pois vai gerar algo como:

UPDATE dados SET nome='',outracoluna='xxxxxx' WHERE id=1

Leia isto de como evitar:

Um exemplo simples é usar o bindValue ou bindParam:

PDO+bindValue:

$db = new PDO('mysql:host=localhost dbname=teste', 'usuario', 'senha');
    
$stmt = $db->prepare('SELECT * FROM tabela WHERE nome LIKE ?');

$stmt->bindValue(1, '%' . $_GET['busca'] . '%'); // passado diretamente

$stmt->execute();

PDO+bindParam:

$stmt = $db->prepare('SELECT * FROM tabela WHERE nome LIKE :consulta');

$stmt->bindParam(':consulta', $nome);

$nome = '%' . $_GET['consulta'] . '%';

Mysqli+bind_param:

mysqli só trabalha com bind_param, ou seja não existe um bind_value

$db = new mysqli('localhost', 'usuario', 'senha', 'teste');

$stmt = $db->prepare('SELECT * FROM tabela WHERE nome LIKE ?');

if(!$stmt){
    echo 'erro na consulta: '. $db->errno .' - '. $db->error;
} else {
    $stmt->bind_param('s', $nome);

    $nome = '%' . $_GET['consulta'] . '%';

    $stmt->execute();
}

bindValue e bindParam

  • bindParam trabalha com referencias, ou seja só deve-se usar variáveis e constantes. Se for uma variável o valor pode ser alterado posteriormente, mas antes do execute

  • bindValue trabalha com qualquer tipo de valor, variável constante ou passado diretamente

Leia mais em: Qual a diferença entre bindParam e bindValue?

Correct answer by Guilherme Nascimento on October 21, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP