Vulnerabilidades de injeções de SQL ao usar modelos SQL do Zend Framework

15

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&section=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:

  1. Qual é a melhor maneira de evitar esse cenário?
  2. 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.

JohnyFree
fonte
11
Você pode usar: $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.
ash
Acabei de perceber que esse cenário só é possível se o valor for inteiro. Se o valor for varchar, sempre haverá 'sinal antes do (sinal e, portanto, (SELECTou 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.
JohnyFree
E se você começar com o fechamento do '? 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'"
7ochem
@ 7ochem nesse caso, você DEVE ligar parâmetro usando? e 'se tornará'. Mas se você usar um inteiro valor, então você não para vinculá-lo desde que você pode limpá-lo usando intval function () php e 'algo se tornará 0.
JohnyFree

Respostas:

8

Valide sua entrada!

Tão bom quanto você puder.

Algumas sugestões para sua validação:

  1. 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.

  2. 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:

    $validator = new Zend_Validate_Hostname();
    if ($validator->isValid($hostname)) {
        //hostname is valid - continue
    }
  3. 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.

    $allowedDomains = array('www.domain1.tld','www.domain2.tld');
  4. 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).

Anna Völkl
fonte