As outras respostas já cobrem o que você precisa saber. Mas talvez ajude a esclarecer um pouco mais:
Existem DUAS COISAS que você precisa fazer:
1. Valide os dados do formulário.
Como a resposta de Jonathan Hobbs mostra muito claramente, a escolha do elemento html para a entrada do formulário não oferece nenhuma filtragem confiável para você.
A validação geralmente é feita de uma forma que não altera os dados, mas que mostra o formulário novamente, com os campos marcados como "Corrija isso".
A maioria das estruturas e CMSs tem construtores de formulários que o ajudam nessa tarefa. E não apenas isso, eles também ajudam contra o CSRF (ou "XSRF"), que é outra forma de ataque.
2. Sanitize / Escape variáveis em instruções SQL.
.. ou deixe que as declarações preparadas façam o trabalho por você.
Se você construir uma instrução (My) SQL com quaisquer variáveis, fornecidas pelo usuário ou não, você precisa escapar e citar essas variáveis.
Geralmente, qualquer variável inserida em uma instrução MySQL deve ser uma string ou algo que o PHP pode ser transformado de forma confiável em uma string que o MySQL pode digerir. Por exemplo, números.
Para strings, você precisa escolher um dos vários métodos para escapar da string, ou seja, substituir quaisquer caracteres que teriam efeitos colaterais no MySQL.
- No antigo MySQL + PHP, mysql_real_escape_string () faz o trabalho. O problema é que é muito fácil esquecê-lo, então você deve usar instruções preparadas ou construtores de consulta.
- No MySQLi, você pode usar instruções preparadas.
- A maioria das estruturas e CMSs fornece construtores de consulta que o ajudam nessa tarefa.
Se estiver lidando com um número, você pode omitir o escape e as aspas (é por isso que as instruções preparadas permitem especificar um tipo).
É importante ressaltar que você escapa das variáveis para a instrução SQL, e NÃO para o próprio banco de dados . O banco de dados armazenará a string original, mas a instrução precisa de uma versão com escape.
O que acontece se você omitir um desses?
Se você não usar a validação de formulário , mas limpar sua entrada SQL, poderá ver todos os tipos de coisas ruins acontecendo, mas não verá injeção de SQL! (*)
Primeiro, ele pode levar seu aplicativo a um estado que você não planejou. Por exemplo, se você deseja calcular a idade média de todos os usuários, mas um usuário deu "aljkdfaqer" para a idade, seu cálculo falhará.
Em segundo lugar, pode haver todos os tipos de outros ataques de injeção que você precisa considerar: Por exemplo, a entrada do usuário pode conter javascript ou outras coisas.
Ainda pode haver problemas com o banco de dados: por exemplo, se um campo (coluna da tabela do banco de dados) estiver limitado a 255 caracteres e a string for maior do que isso. Ou se o campo aceitar apenas números e você tentar salvar uma string não numérica. Mas isso não é "injeção", é apenas "travar o aplicativo".
Mas, mesmo se você tiver um campo de texto livre onde permite qualquer entrada sem nenhuma validação, você ainda pode salvar isso no banco de dados assim, se você escapar apropriadamente quando for para uma instrução de banco de dados. O problema surge quando você deseja usar esta string em algum lugar.
(*) ou isso seria algo realmente exótico.
Se você não escapar variáveis para instruções SQL , mas validar a entrada do formulário, ainda poderá ver coisas ruins acontecendo.
Em primeiro lugar, você corre o risco de que, ao salvar os dados no banco de dados e carregá-los novamente, não sejam mais os mesmos dados, "perdidos na tradução".
Em segundo lugar, isso pode resultar em instruções SQL inválidas e, portanto, travar seu aplicativo. Por exemplo, se qualquer variável contém uma aspa ou caractere de aspas duplas, dependendo do tipo de aspas que você usa, você obterá uma instrução MySQL inválida.
Em terceiro lugar, ele ainda pode causar injeção de SQL.
Se sua entrada de usuário de formulários já estiver filtrada / validada, a injeção SQl intencional pode se tornar menos provável, SE sua entrada for reduzida a uma lista de opções codificada ou se for restrita a números. Mas qualquer entrada de texto livre pode ser usada para injeção de SQL, se você não escapar adequadamente das variáveis nas instruções SQL.
E mesmo que você não tenha nenhuma entrada de formulário, você ainda pode ter strings de todos os tipos de fontes: lidas do sistema de arquivos, copiadas da Internet, etc. Ninguém pode garantir que essas strings sejam seguras.
<select>
entrada. Na verdade, até mesmo um usuário ligeiramente técnico pode adicionar opções adicionais usando o console do navegador. se você mantiver uma lista de permissões de array de valores disponíveis e comparar a entrada com ela, pode mitigar isso (e deve, porque evita valores indesejados)