Kompletny przewodnik po SQL injection dla developerów PHP (i nie tylko) Krzysztof Kotowicz PHP Developer http://web.eskot.pl Medycyna Praktyczna krzysztof@kotowicz.net.

Slides:



Advertisements
Podobne prezentacje
Copyright © The OWASP Foundation Permission is granted to copy, distribute and/or modify this document under the terms of the OWASP License. The OWASP.
Advertisements

Copyright © The OWASP Foundation Permission is granted to copy, distribute and/or modify this document under the terms of the OWASP License. The OWASP.
Wprowadzenie do informatyki Wykład 6
Procedury wyzwalane Procedura wyzwalana (ang. trigger) - stanowi kod użytkownika przechowywany wewnątrz bazy i uruchamiany w określonych sytuacjach np.
Projektowanie bazy danych
Skrypty, procedury przechowywane i wyzwalane
Object-Relational Mapper for PHP
Ludwik Antal - Numeryczna analiza pól elektromagnetycznych –W10
SQL – Strukturalny język zapytań
SQL INJECTION Wykorzystanie błędów w językach skryptowych
Bazy danych II Instrukcja SELECT Piotr Górczyński 25/08/2001.
Bezpieczeństwo aplikacji WWW
Domy Na Wodzie - metoda na wlasne M
PHP + MySQL część II.
Język SQL ma ciekawe możliwości tworzenia zapytań
25/08/ Bazy danych II Piotr Górczyński MS Access – Action Query.
18/11/ Języki programowania 1 Piotr Górczyński Łączenie z bazą danych.
Metody autoryzacji użytkowników wymaga integracji z systemem operacyjnym nie wymaga logowania mała pewność mechanizmu wymaga logowania duża pewność mechanizmu.
PREPARATYWNA CHROMATOGRAFIA CIECZOWA.
Ministerstwo Gospodarki Poland'sexperience Waldemar Pawlak Deputy Prime Minister, Minister of Economy March 2010.
Bezpieczeństwo Procedury składowane Funkcje i Wyzwalacze
ZSBD PL/SQL CZĘŚĆ 3 Wykład 5 Prowadzący: dr Paweł Drozda.
WYZWALACZE (TRIGGERY) Wyzwalacz jest specjalnym rodzajem procedury składowanej, która może być wykonana w odpowiedzi na jedną z trzech sytuacji: UPDATE.
Zapytania SQL: wydajność i optymalizacja
Wykład 8 Wojciech Pieprzyca
Wykład 2 struktura programu elementy języka typy zmienne
1 Języki i techniki programowania prowadzący dr Grzegorz Filipczyk.
Praca Inżynierska „Analiza i projekt aplikacji informatycznej do wspomagania wybranych zadań ośrodków sportowych” Dyplomant: Marcin Iwanicki Promotor:
Język SQL (Structured Query Language) DDL (Data Definition Language)
Przykład włamania do aplikacji internetowej poprzez modyfikację zapytań SQL Skrypty ASP Serwer bazy danych MS SQL Server Piotr Kuźniacki BDi.
Jak przeżyć w Internecie? Czyli o bezpieczeństwie słów kilka… Michał Jankowski MJ Software Solutions Services.
Wprowadzenie do JSP Copyright © Politecnico di Milano September 2003 Translation: Kamil Żyła, Politechnika Lubelska.
Podstawy C# Grupa .NET PO.
SQL – Structured Query Language (3)
MySQL – ODBC - ACCESS.
Wirtualna baza SQL zgodna z SQL Server SQL as a Service
Instrukcje: CREATE, INSERT, UPDATE, DELETE, DROP
Użytkownicy i przywileje Sesja - przykład Błędy Komunikacja międzyskryptowa Wykład 83PD Technologie internetowe.
KOLEKTOR ZASOBNIK 2 ZASOBNIK 1 POMPA P2 POMPA P1 30°C Zasada działanie instalacji solarnej.
SQL - Structured Query Language
Aplikacje bazodanowe ADO.NET PHP i MySQL
Tworzenie Aplikacji Internetowych
Tworzenie Aplikacji Internetowych dr Wojciech M. Gańcza 8.
Tworzenie Aplikacji Internetowych dr Wojciech M. Gańcza 3.
Komendy SQL do pracy z tabelami i bazami
Systemy zarządzania treścią Wykład 5
Bazy Danych Wykład 7 Wojciech St. Mościbrodzki
EcoCondens Kompakt BBK 7-22 E.
EcoCondens BBS 2,9-28 E.
PL/SQL – dalsza wędrówka
Programowanie w języku C++
User experience studio Użyteczna biblioteka Teraźniejszość i przyszłość informacji naukowej.
1 SBD, L.Banachowski Podstawy SQL - języka relacyjnych i obiektowo-relacyjnych baz danych (SQL2, SQL'1999, Oracle) Powtórzenie wyk ł adu 3.
Testogranie TESTOGRANIE Bogdana Berezy.
Jak Jaś parował skarpetki Andrzej Majkowski 1 informatyka +
Jak przeżyć w Internecie? Czyli o bezpieczeństwie słów kilka… Michał Jankowski MJ Software Solutions Services.
1 SBD, L.Banachowski Zaawansowane cechy SQL Powtórzenie wyk ł adu 5.
Autor: Damian Urbańczyk
Entity Framework worth it or not?
Współrzędnościowe maszyny pomiarowe
Elementy geometryczne i relacje
Strategia pomiaru.
Piotr Czapiewski Wydział Informatyki ZUT Wykład 2.
Komendy SQL do pracy z danymi
.NET i Bazy Danych Projekt: Wadim Grasza.
Współpraca PHP i MySQL Wygodniejszym i wydajniejszym sposobem przechowywania i korzystania z danych zapisanych na serwerze jest współpraca z relacyjna.
ASP.NET Dostęp do bazy danych z poziomu kodu Elżbieta Mrówka-Matejewska.
Projekt „NEW-TECH Program rozwoju praktycznych kompetencji nauczycieli zawodów branż nowych technologii” jest współfinansowany przez Unię Europejską Projekt.
Strukturalny język zapytań SQL - historia
Technologie Informacyjne Bazy danych
Zapis prezentacji:

Kompletny przewodnik po SQL injection dla developerów PHP (i nie tylko) Krzysztof Kotowicz PHP Developer http://web.eskot.pl Medycyna Praktyczna krzysztof@kotowicz.net 10.03.2010 1

Plan prezentacji Co to jest SQL injection? Dlaczego SQL injection jest groźne (demo)? Jak się bronić? Prepared statements Escape'owanie Procedury składowane Metody uzupełniające Podsumowanie 2 2

Omawiane bazy danych (RDBMS) MySQL Oracle MS SQL Server W mniejszym stopniu: PostgreSQL SQLite 3 3

Omawiane projekty PHP PDO – PHP data objects Doctrine 1.2 Propel 1.4 Wspólny interfejs dla różnych RDBMS Doctrine 1.2 ORM (Object Relational Mapper) używany m.in. we frameworku Symfony Propel 1.4 ORM konkurencyjny dla Doctrine Używany we frameworku Symfony Zend Framework 1.10 Popularny framework MVC dla PHP MDB2 2.4.1 Warstwa abstrakcji bazy danych (DBAL) Dystrybuowany przez PEAR 4 4

Co to jest SQL injection? 5 5

SQL injection – krótka definicja Jest to rodzaj ataku na aplikacje internetowe. Polega na tym, że dane od użytkownika pochodzące z: URL: www.example.com?id=1 Formularzy: email=a@example.com Innych elementów: np. cookie, nagłówki HTTP zostają zmanipulowane tak, że w podatnej aplikacji zostaje wykonane „wstrzyknięte” przez atakującego polecenie SQL. 6 6

Przykład – formularz logowania SELECT * FROM users WHERE login = '{$login}' and password_hash = MD5('{$password}') $login = "' or 1=1 -- "; $password = "dowolne"; SELECT * FROM users WHERE login = '{$login}' and password_hash = MD5('{$password}') SELECT * FROM users WHERE login = '{$login}' and password_hash = MD5('{$password}') $login = "' or 1=1 -- "; $password = "dowolne"; // zamierzalismy osiagnac to (kod \ dane) SELECT * FROM users WHERE login = '' or 1=1 -- ' and password_hash = MD5('dowolne') SELECT * FROM users WHERE login = '{$login}' and password_hash = MD5('{$password}') $login = "' or 1=1 -- "; $password = "dowolne"; // zamierzalismy osiagnac to (kod \ dane) SELECT * FROM users WHERE login = '' or 1=1 -- ' and password_hash = MD5('dowolne') // serwer interpretuje to tak Użytkownik jest zalogowany bez znajomości loginu ani hasła 7 7

Dlaczego jest groźne? DEMO 8 8

Nieuprawniony dostęp do aplikacji Czym grozi podatność na SQL injection? Nieuprawniony dostęp do aplikacji Dostęp do całej zawartości bazy / baz na serwerze Denial of service Możliwość modyfikacji danych w bazie Przeczytanie / zapisanie pliku na serwerze Wykonanie kodu na serwerze 9 9

Kilka faktów Podatności na injection na pierwszym miejscu OWASP Top 10 2010 RC Odpowiada za 40–60% przypadków wycieku danych [1] [2] Obecne techniki ataku są bardzo zaawansowane i często automatyzowane Podatność nie tylko w części WHERE Czasem celem jest zepsucie zapytania Codziennie znajdowane podatności, nawet w nowych aplikacjach 10 10 10

Jak się bronić? 11 11

Jak się bronić przed SQL injection? Źródło podatności - łączenie kodu z danymi Metody obrony Oddzielenie kodu od danych prepared statements stored procedures Escape'owanie danych SELECT * FROM users WHERE login = 'login' 12 12

Jak się bronić? Prepared statements 13 13

Prepared statements – zasada działania Przygotowujemy polecenie SQL (string) W miejsce danych wstawiamy znaczniki Przesyłamy polecenie na serwer Podajemy zestaw danych do polecenia Wykonujemy polecenie Odbieramy rezultat 3, 4, 5 można powtarzać... Czyścimy polecenie WHERE a = ? ... WHERE a = :col PREPARE EXECUTE 14 14

Prepared statements - przykład Przykład działania (PDO) // przygotowujemy zapytanie $stmt = $dbh->prepare("INSERT INTO SUMMARIES (name, sum) VALUES (:name, :sum)"); // podajemy wartosci zmiennych – RAZEM Z TYPAMI! $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':sum', $sum, PDO::PARAM_INT); // podajemy wartości zmiennych $name = 'something'; $value = 1234; // wykonujemy zapytanie $stmt->execute(); $stmt = null; //zwalniamy pamiec 15 15

Prepared statements - zalety Polecenia SQL są całkowicie oddzielone od przetwarzanych danych Brak możliwości wstrzyknięcia kodu SQL Polecenie SQL jest przez serwer kompilowane tylko raz – potencjalne zwiększenie wydajności zapytań $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':sum', $sum, PDO::PARAM_INT); // petla po danych... foreach ($do_bazy as $name => $value) { $stmt->execute(); } 16 16

Prepared statements - uwagi Nie wszystkie typy poleceń można parametryzować Nie w każdym miejscu polecenia można wstawić parametr Samo ich użycie nie wymusza stosowania parametrów Czasem są emulowane (ale to dobrze!) -- blad SELECT * FROM :tabela SELECT :funkcja(:kolumna) FROM :widok -- nie tego się spodziewacie SELECT * FROM tabela WHERE :kolumna = 1 SELECT * FROM tabela GROUP BY :kolumna 17 17

Prepared statements w Doctrine Używa PDO (emulacja dla Oracle) i prepared statements Zamiast SQL używa własnego języka – DQL $q = Doctrine_Query::create() ->select('u.id') ->from('User u') ->where('u.login = ?', ‘mylogin'); echo $q->getSqlQuery(); // SELECT u.id AS u__id FROM user u // WHERE (u.login = ?) $users = $q->execute(); 18 18

Prepared statements w Doctrine cd. Wciąż można „wpaść” Trzeba poprawić na: NIGDY nie umieszczaj danych wejściowych bezpośrednio w treści zapytań $q = Doctrine_Query::create() ->update('Account') ->set('amount', 'amount + 200') ->where("id > {$_GET['id']}"); ->where("id > ?", (int) $_GET['id']); 19 19

Prepared statements w Propel Podobnie jak Doctrine, oparty na PDO // poprzez Criteria $c = new Criteria(); $c->add(AuthorPeer::FIRST_NAME, "Karl"); $authors = AuthorPeer::doSelect($c); // poprzez customowy SQL (czasem jest latwiej) $pdo = Propel::getConnection(BookPeer::DATABASE_NAME); $sql = "SELECT * FROM skomplikowany_sql JOIN cos_jeszcze_gorszego USING cos_tam WHERE kolumna = :col)”; $stmt = $pdo->prepare($sql); $stmt->execute(array('col' => 'Bye bye SQLi!'); 20 20

Prepared statements w Zend Framework PDO (+ mysqli + oci8 + sqlsrv) // prepare + execute $stmt = $db->prepare('INSERT INTO server (key, value) VALUES (:key,:value)'); $stmt->bindParam('key', $k); $stmt->bindParam('value', $v); foreach ($_SERVER as $k => $v) $stmt->execute(); // prepare + execute w jednym kroku $stmt = $db->query('SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?', array('goofy', 'FIXED')); while ($row = $stmt->fetch()) echo $row['bug_description']; 21 21

Emuluje PS, jeśli baza ich nie wspiera MDB2 Oparty na konkretnych sterownikach baz danych (mysql, oci8, mssql, ...) Emuluje PS, jeśli baza ich nie wspiera $types = array('integer', 'text', 'text'); $stmt = $mdb2->prepare('INSERT INTO numbers VALUES (:id, :name, :lang)', $types); $data = array('id' => 1, 'name' => 'one', 'lang' => 'en'); $affectedRows = $stmt->execute($data); $stmt->free(); 22 22

Prepared statements - podsumowanie Oferują bardzo dobre zabezpieczenie (jeśli użyte poprawnie) Łatwe w użyciu, niewielkie zmiany w kodzie Dobre wsparcie we frameworkach Mają swoje ograniczenia Czasem muszą być uzupełniane innymi metodami zabezpieczeń 23 23

Jak się bronić? Escape'owanie danych 24 24

Escape'owanie – zasada działania Dane i polecenia wciąż trzymamy w jednej zmiennej, ale zabezpieczamy je Liczby Rzutowanie na (int) / (float) – nie is_numeric [1]! Teksty - zwykle otoczone apostrofami: ' Jeśli w tekście również są apostrofy, trzeba je odróżnić od apostrofu „kończącego” Apostrof wewnątrz danych jest poprzedzany znakiem specjalnym, np. "\" Reguły escape'owania zależą od kontekstu! .. WHERE pole = 'DANE TEKSTOWE' AND ... 25 25

Escape'owanie – kontekst addslashes() Returns a string with backslashes before characters that need to be quoted in database queries etc. These characters are single quote ('), double quote ("), backslash (\) and NUL (the NULL byte). / Źródło: php.net manual / Czy jesteś bezpieczny? $user = addslashes($_GET['u']); $pass = addslashes($_GET['p']); $sql = "SELECT * FROM users WHERE username = '{$user}' AND password = '{$pass}'"; $ret = exec_sql($sql); 26 26

NIE

Escape'owanie – kontekst cd. Różne RDBMS mają różne sposoby escape'owania danych (zależy to też od konfiguracji bazy) addslashes() tylko „przypadkiem” działa dla MySQL RBDMS Funkcja mam 'apostrofy' PDO $pdo->quote($val, $type) n/d (różnie) MySQL (mysql) mysql_real_escape_string mam \'apostrofy\' MySQL (mysqli) mysqli_real_escape_string Oracle (oci8) n/d - str_replace() mam ''apostrofy'' SQLite sqlite_escape_string MS SQL (mssql) PostgreSQL pg_escape_string() Sprawdzic ansi mode 28 28

Escape'owanie – kontekst cd. // SELECT * FROM users WHERE username = // '{$user}' AND password = '{$pass}' $_GET['u'] = "cokolwiek'"; $_GET['p'] = " or 1=1 -- "; // MySQL widzi to tak: SELECT * FROM users WHERE username = 'cokolwiek\'' AND password = ' or 1=1 -- ' // SQLite / MS SQL / Oracle / PostgreSQL - tak: Nie używaj addslashes(), używaj funkcji konkretnej bazy Czy teraz jesteś bezpieczny? 29 29

PRAWIE

Pułapki escape'owania – zestawy znaków Błędy wykryte w 2006 r. w PostgreSQL i MySQL [1] [2] W niektórych wielobajtowych zestawach znaków pomimo escape’owania można doprowadzić do SQL injection \ zostaje „połknięty” przez wielobajtowy znak Przykład: BF 27 [ ¬ ' ]  BF 5C 27 [ ¬ \ ' ] Pierwsze dwa bajty to w charsecie GBK znak ¿ Serwer „zobaczy” ciąg ¿' 31 31

Pułapki escape'owania – zestawy znaków Podatne są różne azjatyckie zestawy znaków Na szczęście nie UTF-8! W PostgreSQL zastosowano escape'owanie poprzez '' (zamiast \') W mysql_real_escape_string() zastosowano uwzględnianie bieżącego zestawu znaków Nie zawsze zadziała! [1] [2] Kontekst to również zestaw znaków 32 32

Escape'owanie – nazwy obiektów Nazwy kolumn, tabel, baz Nie ma dobrej ogólnej metody na ich escape'owanie W różnych bazach różne listy słów zarezerwowanych, różne długości nazw itp. Jeśli musisz pobierać te nazwy od użytkownika, zastosuj whitelisting (blacklisting w ostateczności) 33 33

Escape'owanie – nazwy obiektów cd. Przykład – sortowanie po kolumnie Jest podatność w $order, ale nie możesz użyć escape'owania $cat_id = (int) $_GET['cid']; $order = $_GET['column']; $stmt = $pdo->prepare("SELECT * FROM products WHERE cid = :cid ORDER BY $order"); $stmt->bindParam(':cid', $cat_id, PDO::PARAM_INT); if ($stmt->execute()) { ... } 34 34

Escape'owanie – nazwy obiektów cd. Whitelisting Blacklisting $columns = array( // lista dozwolonych kolumn 'product_name','cid','price', ); if (!in_array($order, $columns, true)) $order = 'product_name'; // wartosc domyslna // tylko znaki a-z i _ $order = preg_replace('/[^a-z_]/', '', $order); // max 40 znakow $order = substr($order, 0, 40); 35 35

PDO::quote($value, $type, $len) Długość i typ bywają ignorowane! Escape'owanie w PDO PDO::quote($value, $type, $len) Długość i typ bywają ignorowane! Liczby najlepiej rzutuj na (int), (float) Teksty – obcinaj ręcznie $quoted = $pdo->quote($input, PDO::PARAM_STR, 40); 36 36

Escape'owanie w Doctrine Uwaga na Doctrine'owe quote()! $q = Doctrine_Query::create(); // nie tak!!! $quoted = $q->getConnection()->quote($input, 'text'); $q->update('User')->set('username', $quoted); // quote() zamienia ' na '' - exploit (MySQL): $input = 'anything\\\' where 1=1 -- '; // trzeba escape'owac poprzez PDO - getDbh(): $quoted = $q->getConnection() ->getDbh() ->quote($input, PDO::PARAM_STR); // 'anything \\\\\\\' where 1=1 -- ' 37 37

Escape'owanie w Propel Poprzez PDO::quote() $pdo = Propel::getConnection(UserPeer::DATABASE_NAME); $c = new Criteria(); $c->add(UserPeer::PASSWORD, "MD5(".UserPeer::PASSWORD.") " ." = " . $pdo->quote($password), Criteria::CUSTOM); 38 38

Escape'owanie w Zend Framework Funkcje quote(), quoteInto() $name = $db->quote("O'Reilly"); // 'O\'Reilly' // uproszczone escape'owanie dla jednej zmiennej $sql = $db->quoteInto("SELECT * FROM products WHERE product_name = ?", 'any string'); 39 39

Escape'owanie w MDB Funkcja quote() // funkcja quote()- trzeba określić typ $query = 'INSERT INTO table (id, itemname, saved_time) VALUES (' . $mdb2->quote($id, 'integer') .', ' . $mdb2->quote($name, 'text') .', ' . $mdb2->quote($time, 'timestamp') .')'; $res = $mdb2->exec($query); 40 40

Escape'owanie danych - podsumowanie Wydaje się proste – zastępowanie tekstu Niestety, tylko się wydaje Musimy znać kontekst (baza danych, charset) Istnieją błędne implementacje Skłania do stosowania niebezpiecznych konstrukcji sklejanie poleceń ignorowanie zmiennych numerycznych Stosowanie dopuszczalne tylko, jeśli Programujemy pod konkretną bazę Nie ma innej możliwości 41 41

Jak się bronić? Procedury składowane 42 42

Procedury składowane Polecenie SQL (lub seria poleceń) zostaje przeniesione na serwer bazy danych i zapisane jako procedura Po stronie klienta procedura zostaje wywołana z określonymi parametrami (danymi) wejściowymi i wyjściowymi W parametrach wyjściowych klient otrzymuje wyniki procedury Dane są formalnie oddzielone od kodu To NIE wystarcza 43 43

Przykład w MS SQL – fragment podatnej procedury Procedury składowane Przykład w MS SQL – fragment podatnej procedury To eval() w kolejnym wcieleniu! CREATE PROCEDURE SP_ProductSearch @prodname varchar(400) AS DECLARE @sql nvarchar(4000) SELECT @sql = 'SELECT ProductID, ProductName, Category, Price FROM Product Where ProductName LIKE ''' + @prodname + '''' EXEC (@sql) ... 44 44

Procedury składowane cd. Przykład tej samej podatności w Oracle CREATE OR REPLACE PROCEDURE SP_ProductSearch(Prodname IN VARCHAR2) AS sqltext VARCHAR2(80); BEGIN sqltext := 'SELECT ProductID, ProductName, Category, Price FROM Product WHERE ProductName LIKE ''' || Prodname || ''''; EXECUTE IMMEDIATE sqltext; ... END; 45 45

Procedury składowane – Dynamic SQL Źródło podatności – Dynamic SQL Dane znów „przemieszane” z kodem w jednej zmiennej, która zostaje wykonana jako polecenie SQL Jak się obronić? Oddziel kod od danych Escape'uj 46 46

Procedury składowane w MS SQL Oddzielenie danych od kodu użyj sp_executesql razem z listą parametrów CREATE PROCEDURE SP_ProductSearch @prodname varchar(400) = NULL AS DECLARE @sql nvarchar(4000) SELECT @sql = N'SELECT ProductID, ProductName, Category, Price FROM Product Where ProductName LIKE @p' EXEC sp_executesql @sql, N'@p varchar(400)', @prodname 47 47

Procedury składowane w MS SQL cd. Escape'owanie zmiennych tekstowych Przykład: Escape'uj tylko wtedy, kiedy musisz! (używaj sp_executesql z parametrami) Nazwa obiektu QUOTENAME(@v) Tekst <= 128 znaków QUOTENAME(@v,'''') Tekst > 128 znaków REPLACE(@v,'''','''''') SET @cmd = N'select * from authors where lname=''' + REPLACE(@lname, '''', '''''') + N'''' 48 48

Procedury składowane w Oracle Oracle - użyj EXECUTE IMMEDIATE .. USING Escape'owanie - pakiet DBMS_ASSERT CREATE OR REPLACE PROCEDURE SP_ProductSearch(Prodname IN VARCHAR2) AS sqltext VARCHAR2(80); BEGIN sqltext := 'SELECT ProductID, ProductName, Category, Price WHERE ProductName=:p'; EXECUTE IMMEDIATE sqltext USING Prodname; ... END; 49 49 CREATE PROCEDURE SP_ProductSearch @prodname varchar(400) = NULL AS DECLARE @sql nvarchar(4000) SELECT @sql = 'SELECT ProductID, ProductName, Category, Price FROM Product Where ProductName LIKE @prodname' EXEC sp_executesql @sql, N'@prodname varchar(400)', @prodname

Procedury składowane w MySQL Wsparcie dla Dynamic SQL tylko poprzez prepared statements Napisanie podatnych procedur jest trudniejsze niż procedur zabezpieczonych! Wystarczy używać placeholderów zamiast doklejać wartości zmiennych pO tym dodac slajd, jak wywolac procedure w SQL (call / exec) 50 50

Procedury składowane w MySQL cd. PREPARE / EXECUTE USING / DEALLOCATE PREPARE DELIMITER $$ CREATE PROCEDURE get_users_like ( IN contains VARCHAR(40)) BEGIN SET @like = CONCAT("%", contains, "%"); SET @sql = "SELECT * FROM users WHERE uname LIKE ?"; PREPARE get_users_stmt from @sql; EXECUTE get_users_stmt USING @like; DEALLOCATE PREPARE get_users_stmt; END$$ DELIMITER ; 51 51

Procedury składowane w MySQL cd. Lub jeszcze prościej (bezpośrednio) Escape'owanie – funkcja QUOTE() DELIMITER $$ CREATE PROCEDURE get_users_like ( IN contains VARCHAR(40)) BEGIN SET @like = CONCAT("%", contains, "%"); SELECT * FROM users WHERE uname LIKE @like; END$$ DELIMITER ; 52 52

Procedury składowane w PHP Różne wsparcie w zależności od RDBMS Wsparcie zależy od konkretnego sterownika Wspólne API (np. PDO) obsługuje tylko najprostsze wywołania Procedura nic nie zwraca Procedura zwraca prosty rezultat w parametrze OUT Różna obsługa (lub brak) bardziej zaawansowanych wywołań np. pobieranie rekordów z procedur, kursory Wsparcie we frameworkach śladowe Wciąż występują błędy 53 53

Procedury składowane w PDO Wywołanie procedury // MySQL $sql = "CALL get_users_like(:contains)"; // MS SQL – EXEC get_users_like :contains $stmt = $pdo->prepare($sql); $ret = $stmt->execute(array('contains' => $input)); foreach($stmt->fetchAll() as $users) { var_dump($users); } unset($s); 54 54

Procedury składowane w Doctrine/Propel/Zend Framework Doctrine - Brak wsparcia (użyj PDO) Propel – jw. Zend Framework – jw. $pdo = Doctrine_Manager::connection()->getDbh(); $pdo = Propel::getConnection(UserPeer::DATABASE_NAME); $pdo = $db::getConnection(); 55 55

Procedury składowane w MDB2 Trzeba własnoręcznie escape'ować wszystkie parametry $mdb2->loadModule('Function'); $multi_query = $mdb2->setOption('multi_query', true); if (!PEAR::isError($multi_query)) { $result = $mdb2->executeStoredProc('get_users_like', array($mdb2->quote($contains, 'text'))); do { while ($row = $result->fetchRow()) { var_dump($row); } } while ($result->nextResult()); 56 56

Procedury składowane - pułapki Długość zmiennych CREATE PROCEDURE change_password @loginname varchar(50), @old varchar(50), @new varchar(50) AS DECLARE @command varchar(120) SET @command= 'UPDATE users SET password=' + QUOTENAME(@new, '''') + ' WHERE loginname=' + QUOTENAME(@loginname, '''') + ' AND password=' + QUOTENAME(@old, '''') EXEC (@command) GO 57 57

Procedury składowane - podsumowanie Czasochłonne przenoszenie logiki SQL z aplikacji na serwer Nie są łatwo przenośne pomiędzy RDBMS Napisane bezpiecznych procedur i tak wymaga użycia prepared statements lub escape'owania danych Źle zaimplementowane mogą zwiększyć podatność Zarówno wywołanie procedury, jak i jej kod jest podatny Procedura może mieć większe uprawnienia niż kod ją wywołujący Złe wsparcie w PHP i we frameworkach 58 58

Procedury składowane - podsumowanie Mają dużo zalet poza naszym obszarem zainteresowania Można precyzyjnie zarządzać uprawnieniami do procedur Przydatne w wypadku stosowania różnych klientów (Java/.NET + PHP) Mogą zwiększyć wydajność I wiele innych... Wnioski: Pozwalają osiągnąć dobre zabezpieczenie przed SQL injection, ale przy dużych kosztach. Niezbędne jest zabezpieczanie samego kodu procedur przed SQL injection. 59 59

Jak się bronić? Metody uzupełniające 60 60

Walidacja i filtrowanie danych Kontrola poprawności danych zewnętrznych Odbywa się przed przetwarzaniem tych danych Nie myl z escape'owaniem! Filter INPUT - escape OUTPUT Osobne reguły walidacji dla każdego parametru - sprawdzaj m.in. Typ zmiennej Skalar / tablica Wartości min / max Długość danych tekstowych! [1] 61 61

Uzupełniające metody obrony Komplementarne do poprzednich! Zasada najmniejszych uprawnień przy łączeniu się do bazy danych Wyłączenie nieużywanych funkcji, kont, pakietów dostarczanych z bazą danych Regularne aktualizowanie serwera bazy danych Dobra konfiguracja PHP i bazy magic_quotes_* = false display_errors = false Dobrze zaprojektowana baza danych 62 62

Podsumowanie Zwracaj uwagę na SQL injection - pojedynczy błąd może wiele kosztować! Preferuj rozwiązania kompleksowe - np. frameworki Filtruj wszystkie dane wejściowe Pamiętaj o typach i długościach zmiennych Stosuj whitelisting zamiast blacklistingu - to drugie kiedyś zawiedzie! Stosuj prepared statements wszędzie, gdzie możesz Unikaj escape'owania W procedurach składowanych uważaj na Dynamic SQL 63 63

Linki Omawiane projekty sqlmap.sourceforge.net php.net/manual/en/book.pdo.php www.doctrine-project.org propel.phpdb.org/trac framework.zend.com pear.php.net/package/MDB2 O SQL injection www.owasp.org/index.php/SQL_Injection unixwiz.net/techtips/sql-injection.html delicious.com/koto/sql+injection Hack me threats.pl/bezpieczenstwo-aplikacji-internetowych tinyurl.com/webgoat mavensecurity.com/dojo.php krzysztof@kotowicz.net http://blog.kotowicz.net 64 64