Ao ingressar em tabelas, uso modelos SQL do Zend Framework. Como exemplo, modifiquei meu código real, mas acho que você entenderá o ponto:
$this->getSelect()->join(
array('sections' => $sectionsTableName),
'main_table.banner_id = pages.banner_id',
array()
)
->where("sections.section= '$section' OR sections.section = '0' OR (sections.section = '6' AND ? LIKE main_table.url)",$url)
->group('main_table.banner_id');
A página é carregada com ajax e o parâmetro $ section é enviado como parâmetro GET ( www.example.com/controllerName/index/display/3?paremeter1=example§ion=www.example2.com
).
Agora, aqui está o problema se alguém executar algo parecido com isto:
www.example.com/controllerName/index/display/3?paremeter1=example&url=(SELECT 3630 FROM(SELECT COUNT(*),CONCAT(0x7170786a71,(SELECT (ELT(3630=3630,1))),0x717a716b71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)
Dessa maneira, o usuário pode despejar o banco de dados inteiro. Os dados não serão exibidos, mas o SQL ainda executará o dump, o que pode causar sobrecarga no sql.
Questões:
- Qual é a melhor maneira de evitar esse cenário?
- Agora estou preocupado com clientes anteriores. É possível com esse código executar ainda mais ações de risco, como excluir ou alterar tabela? Acho que não, porque você não pode colocar nenhuma outra instrução além de SELECT dentro da subseleção para que DELETE produza erro de sintaxe sql. Estou certo?
UPDATE: Meu exemplo não é uma ilustração adequada da injeção de SQL, porque há seções 'arround $' e, portanto, não será possível fazer a injeção. De qualquer forma, isso seria possível quando se espera um valor inteiro e quando você não filtra a entrada inteira. Veja meu comentário abaixo.
fonte
$db = Mage::getSingleton('core/resource')->getConnection('core_read');
e$db->quote()
mesmo no seu caso, veja$db->quoteInto
. Se$this
é um recurso, você pode fazer:$this->getConnection('core_read')->quoteInto()
se é uma coleção que você poderia fazer:$this->getResource()->getConnection('core_read')->quoteInto()
. nesse sentido. Se isso ajudar a guiá-lo em direção ao seu objetivo.'
sinal antes do(
sinal e, portanto,(SELECT
ou qualquer outra coisa será apenas como string e não funcionará. Quando o campo é inteiro,'
não é necessário e torna possível esse cenário. Mas o número inteiro sempre deve ser filtrado com,intval()
para que isso também não seja problema.'
? Então' AND (SELECT ...) '
? A propósito, não acho que o Zend não esteja citando isso ... E se você usar ligações, o PDO cuidará disso. Apenas nunca use concatenações sting como esta:"sections.section= '$section'"
Respostas:
Valide sua entrada!
Tão bom quanto você puder.
Algumas sugestões para sua validação:
Verifique o comprimento da variável que você obtém via parâmetro GET. Não é necessário aceitar uma sequência longa sem fim.
Valide para um nome de domínio. Que tipo de formato seus nomes de domínio esperados têm? É sempre www.mydomain.tld? Crie uma regex que verifique se há uma correspondência ou (melhor) use
Zend_Validate_Hostname
:Lista de permissões: você sabe quais nomes de domínio esperar? Você pode criar uma lista de domínios permitidos e compará-los. Largue o resto.
Lista negra de nomes de domínio e / ou caracteres: se você espera um nome de domínio, não há necessidade de aceitar outros caracteres além de az, 0-9 e "." (a menos que você esteja trabalhando com nomes de domínio especiais).
fonte