Luki w zabezpieczeniach wstrzykiwania SQL podczas korzystania z modeli SQL Zend Framework

15

Do łączenia tabel używam modeli SQL Zend Framework. Jako przykład zmodyfikowałem mój rzeczywisty kod, ale myślę, że zrozumiesz:

$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'); 

Strona jest ładowana za pomocą ajax, a parametr sekcji $ jest wysyłany jako parametr GET ( www.example.com/controllerName/index/display/3?paremeter1=example&section=www.example2.com).

Teraz jest problem, jeśli ktoś wykona coś takiego:

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)

W ten sposób użytkownik może zrzucić całą bazę danych. Dane nie będą wyświetlane, ale SQL nadal wykona zrzut, który może spowodować przeciążenie sql.

Pytania:

  1. Jaki jest najlepszy sposób na uniknięcie takiego scenariusza?
  2. Teraz martwię się o poprzednich klientów. Czy dzięki temu kodowi można wykonać jeszcze więcej działań związanych z ryzykiem, takich jak delate lub alter table? Chyba nie dlatego, że nie można wstawić żadnej innej instrukcji niż SELECT do podselekcji, aby DELETE spowodowało błąd składniowy sql. Czy mam rację?

AKTUALIZACJA: Mój przykład nie jest prawidłową ilustracją wstrzyknięcia SQL, ponieważ istnieje „znak wokół sekcji $ i dlatego nie będzie możliwe wykonanie zastrzyku. W każdym razie byłoby to możliwe, gdy oczekuje się wartości całkowitej i gdy nie filtruje się liczb całkowitych. Zobacz mój komentarz poniżej.

JohnyFree
źródło
1
Możesz użyć: $db = Mage::getSingleton('core/resource')->getConnection('core_read');a $db->quote()nawet w twoim przypadku spójrz na $db->quoteInto. Jeśli $thisjest zasobem, można zrobić: $this->getConnection('core_read')->quoteInto()czy jest to zbiór można zrobić: $this->getResource()->getConnection('core_read')->quoteInto(). wzdłuż tych linii. Jeśli to pomoże ci poprowadzić cię do celu.
ash
Właśnie zdałem sobie sprawę, że ten scenariusz jest możliwy tylko wtedy, gdy wartość jest liczbą całkowitą. Jeśli wartość jest varchar, to zawsze będzie 'znak przed (znakiem, a zatem (SELECTwszystko inne będzie tak samo jak ciąg znaków i nie będzie działać. Gdy pole jest liczbą całkowitą, 'nie jest potrzebne i umożliwia taki scenariusz. Ale liczba całkowita powinna być zawsze filtrowana, intval()więc nie stanowi to również problemu.
JohnyFree,
Co jeśli zaczniesz od zamknięcia '? Tak ' AND (SELECT ...) '? Nawiasem mówiąc, nie sądzę, że Zend nie cytuje tego ... A jeśli użyjesz powiązań, PDO to załatwi. Po prostu nigdy nie używaj takich "sections.section= '$section'"
żądań
@ 7ochem w takim przypadku MUSISZ związać parametr za pomocą? i „stanie się \”. Ale jeśli użyjesz wartości całkowitej, nie powiąż jej, ponieważ możesz wyczyścić ją za pomocą funkcji php intval () i „coś stanie się 0.
JohnyFree

Odpowiedzi:

8

Sprawdź poprawność wprowadzonych danych!

Tak dobrze, jak tylko możesz.

Kilka sugestii dotyczących walidacji:

  1. Sprawdź długość zmiennej otrzymanej za pomocą parametru GET. Nie trzeba akceptować niekończącego się długiego łańcucha.

  2. Sprawdź poprawność nazwy domeny. Jakiego formatu mają oczekiwane nazwy domen? Czy to zawsze www.mydomain.tld? Utwórz wyrażenie regularne, które sprawdza dopasowanie lub (lepiej) użyj Zend_Validate_Hostname:

    $validator = new Zend_Validate_Hostname();
    if ($validator->isValid($hostname)) {
        //hostname is valid - continue
    }
  3. Biała lista: Czy wiesz, których nazw domen się spodziewać? Możesz utworzyć listę dozwolonych domen i porównać je. Upuść resztę.

    $allowedDomains = array('www.domain1.tld','www.domain2.tld');
  4. Czarne nazwy domen i / lub znaki: jeśli oczekujesz nazwy domeny, nie musisz akceptować żadnych innych znaków niż az i 0-9 i „.” (chyba że pracujesz ze specjalnymi nazwami domen).

Anna Völkl
źródło