Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu internet Kanał ATOM (tag: internet)

Autor wpisu: Athlan, dodany: 28.05.2011 14:40, tagi: sql, php, internet

Dziś bardzo krótko, bez zbędnych dywagacji, czyli tylko i wyłącznie o tablicy $_SERVER. Dbając o bezpieczeństwo aplikacji webowych zwraca się uwagę na wiele czynników, jakimi są SQL injections, przechwytywanie nieprawidłowych parametrów, uogólniające zapytania przepuszczające maskę % w LIKE zapytaniu do baz, XSS‘y w $_POST, $_GET.

I finalnie… wiele osób zapomina (a jeszcze więcej nie jest tego świadom) o możliwości wstrzyknięcia szkodliwych danych w $_SERVER['HTTP_X_FORWARDED_FOR'];. Konsekwencje są oczywiście katastrofalne.

O ile sama walidacja jest rzeczą wtórną, diabeł tkwi w trzech szczegółach:

  1. Rzecz trywialna, ale pamiętajmy, że w naturalnym procesie użytkowania przeglądarki, w nagłówku może zostać zwrócony nie tylko jeden adres IP, a kilka oddzielonych przecinkiem, w tym localhost‘y (standard nagłówka X-Forwarded-For).
  2. Wstrzyknięcie Javascriptów jest możliwe, ale notabene najmniej szkodliwe, bo do spreparowania nagłówka potrzebny jest bardziej zaawansowany proces (dajmy na to Data Tamping, który przedstawię poniżej), np. niż wklejenie syfu w linku/obrazku i przesłanie go komuś przez komunikator, żeby wykraść jego ciasteczka sesyjne document.cookie i przesłać je sobie na serwer w dowolny sposób, zatem atakowi nie ulegną osoby trzecie.
  3. Niepoprawność danych, które można zmanipulować, jest chyba rzeczą oczywistą: nieprzepuszczenie takich danych przez filtry może skutkować złymi wartościami zwracanymi np. przez ip2long() i zapis w zupełności nieprzydatnych nam później danych do bazy.
  4. ale największe nieprzyjemności możemy mieć przez spreparowanie lewych zapytań do baz danych, o ile nie używamy sprawdzonych ORM lub czegokolwiek, co pomaga nam filtrować wartości do niej przekazywane i używane w warunkach zapytań (data binding).

Przykład tampingu danych, żeby spreparować niepożądane efekty.

Mamy bardzo prosty, niebezpieczny kod funkcji, która pobiera pierwszy adres na liście adresów oddzielonych przecinkami z $_SERVER['HTTP_X_FORWARDED_FOR'] o ile istnieje, natomiast w przeciwnym wypadku $_SERVER['REMOTE_ADDR']:

< ?php
 
function getUserIp()
{
  if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    return trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
 
  return $_SERVER['REMOTE_ADDR'];
}
 
$sUserIP = getUserIp();
 
echo 'Hi "' . $sUserIP . '"!'; // first bug while display.
var_dump(ip2long($sUserIP)); // second bug while transforming data.
 
?>

Pora na przykład manipulacji takich danych.

  • Będziemy używać Tamper Data dla Firefox’a.Dość popularny wśród developerów addon do Firefox’a, pozwala zmodyfikować dane $_POST, $_GET, $_COOKIE, nagłówki, “w locie żądania” etc.
  • Po instalacji w menu Narzędzia pojawi się pozycja Dane Tamper, która uruchamia okienko do podsłuchiwania żądań. Po kliknięciu Rozpocznij podsłuchujemy wszystkie wychodzące żądania z naszej przeglądarki. Każde żądanie nie zostanie przepuszczone, dopóki go nie zmanipulujemy klikając Tamper, lub przepuścimy dalej klikając Wyślij.
  • Jeżeli zdecydujemy się Tamper’ować żądanie, naszym oczom ukaże się okno z parametrami. Klikamy prawym przyciskiem myszy na listę parametrów, wybieramy Dodaj i wpisujemy nasz przykładowy, brzydki dla aplikacji nagłówek: X_FORWARDED_FOR=<script>alert('Test.')</script>

Naszym oczom ukazują się co najmniej dwa błędy. Pierwszy to błąd prezentacji danych, który wykorzystuje <script>. O ile nie musimy się tym przejmować, bo naturalnie takie żądania nie są tak łatwo wysyłane, użytkownik nie może paść ofiarą ataku przez kliknięcie w link, który np. ukradnie mu ciasteczka. Dane nagłówkowe nie są w stanie być zmodyfikowane poprzez kliknięcie w link, podobnie jak z danymi $_POST (oczywiście mówimy o przypadkach trywialnych, bez javascript’owych wymuszanych submitów targetowanych do np. ramek).

Znacznie poważniejszym błędem jest konsekwencja wadliwego formatu danych, które nasza funkcja bagatelizuje. Po pierwsze mamy fałszywe dane zwracane przez ip2long(), po drugie kto powiedział, że właśnie z tej funkcji korzystamy, a nie zapisujemy danych plain’em i nie bindujemy pofiltrowanych danych lub instrukcji warunkowych zapytania przez np. sprawdzony ORM.

Rozwiązanie problemu.

Edit: Jak słusznie zauważył Zyx, zapomniałem o tym wspomnieć, że skoro mogą znaleźć się tam dowolne dane przesłane od użytkownika, nie należy tego pola traktować jako wyznacznik, że jest to numer jego IP, jest ono bezużyteczne i powoduje potencjalną lukę. Poza zabezpieczeniami to podstawowy argument, żeby o polu zapomnieć i używać $_SERVER['REMOTE_ADDR'].

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Tomasz Kowalczyk, dodany: 10.05.2011 21:28, tagi: internet

Cygwin to bardzo przydatne narzędzie każdego użytkownika Windowsa, który chce poczuć "zew Linuksa" na swojej maszynie bez instalacji tego systemu. Jest jednak mały haczyk - nie wszystkie programy są dostępne jako wersje dla Cygwina, a te, które są, bardzo często są poukrywane w różnych dziwnych miejscach, przez co ich instalacja sprawia sporo problemów. Cygwin: Jak [...]

Autor wpisu: Tomasz Kowalczyk, dodany: 08.05.2011 21:33, tagi: internet

Przeglądając różne informacje w Internecie trafiłem na stronę skierowanego w stronę programistów konkursu "Potyczki Algorytmiczne", edycja 2011. Jednym z organizatorów jest wydział Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego [MIMUW], co gwarantuje dobry poziom zawodów.  Jako, że lubię czasem sprawdzić swoje umiejętności programistyczne, zarejestrowałem się w serwisie. Zapraszam do lektury krótkiego komentarza i analizy rozwiązania pierwszego, [...]

Autor wpisu: batman, dodany: 29.04.2011 12:00, tagi: internet

Jedni go kochają, inni nienawidzą. Można go poznać w przysłowiowe 24 godziny. Nie ma projektu, którego nie dałoby się w nim stworzyć. O jakim języku mowa? Oczywiście o PHP – najpopularniejszym i najtańszym języku do tworzenia dynamicznych stron internetowych. Zazwyczaj od tego języka zaczyna się przygoda/droga przez mękę (niepotrzebne skreślić) z tworzeniem szeroko rozumianych stron www. Pierwsze kroki stawiają w nim już uczniowie gimnazjum, z których za kilka, może kilkanaście lat, wyrośnie nowe pokolenie twórców kolejnych frameworków, CMS-ów oraz bibliotek. Wokół PHP zbudowana jest ogromna społeczność wymieniająca się wiedzą, doświadczeniem oraz służąca pomocą wszystkim, którzy chcą się PHP nauczyć.

Społeczność ta znalazła się ostatnimi laty na celowniku (w dobrym tego słowa znaczeniu) Microsoftu. Ktoś gdzieś w korporacji dostrzegł, iż ludzie wybierają technologie, oferujące mniejsze możliwości, ale prostsze w nauce i tańsze. Ze świecą szukać nastoletniego programisty ASP.NET potrafiącego z niczego zrobić działający sklep internetowy. Jeszcze większa świeca będzie potrzebna do znalezienia nastolatka, którego stać będzie na hosting aplikacji stworzonej w ASP.NET.

Microsoft wyszedł naprzeciw potrzebom młodych programistów i zaczął udostępniać darmowe wersje (pomijam tutaj licencje akademickie i inne projekty niedostępne dla szerszego grona) Visual Studio, flagowego produktu MS przeznaczonego dla programistów. Razem z Visual Studio pojawiła się wersja Express bazy danych SQL Server. Kwestia ceny została rozwiązana (za wyjątkiem hostingu, ale o tym za chwilę). Pozostał problem złożoności platformy .NET i wysokiego progu wejścia. Tutaj pojawia się coś, co większość programistów PHP zna i lubi – MVC, a dokładniej rzecz ujmując ASP.NET MVC.

Dalej sprawy potoczyły się szybko. Web Platform Installer, WebMatrix, NuGet, CodePlex, wtyczki do Eclipse oraz prężnie działająca społeczność spowodowały, iż czas od rozpoczęcia nauki do pierwszego działającego projektu skrócił się do wspomnianych 24 godzin. Jedyną skazą na tym pięknym obrazku jest brak taniego hostingu. Microsoft nie pozostał głuchy na narzekania programistów i niedługo w Polsce pojawi się firma oferująca hosting w przystępnych cenach.

Co do tego wszystkiego ma tytułowy MIX11? Wbrew pozorom bardzo wiele. To właśnie na tej konferencji doszedłem do wniosku, iż Microsoft w końcu pokazał ludzką twarz i otworzył się na niezależnych developerów. Zamiast siłą przejmować rynek, dostosowuje swoje produkty do potrzeb programistów i użytkowników. Zamiast iść w zaparte i wciskać innym swoje rozwiązania, korzysta ze sprawdzonych pomysłów i technologii (wystarczy wspomnieć migrację blogów na WordPressa).

Pierwsze dwa dni MIX-a spędziłem na sesjach. Pierwotnie zakładałem ścieżkę frontendowca, czyli HTML, CSS, jQuery, itp. Skończyło się na wymieszaniu powyższych z .NET. O ile tematyka związana z warstwą prezentacji nie zrobiła na mnie dużego wrażenia, tak sesja „An Overview of the MS Web Stack of Love” prowadzona przez Scotta Hanselmana powaliła na kolana. Przez godzinę Scott Hanselman był w stanie zaprezentować Entity Framework, NuGet, IIS Express, ASP.NET MVC oraz WebMatrix. Do tego wszystkiego ponabijał się trochę ze stylu Metro. Nie dało się nie zauważyć, iż wszystko było mniej toporne, bardziej przyjazne użytkownikowi i nie wymagające wiedzy tajemnej. Cały ten straszny dotnetowy świat został sprytnie schowany, dzięki czemu początkujący programista nie zostanie przytłoczony ogromem wiedzy, jaką musi przyswoić.

Trzeciego dnia konferencji większość czasu poświęciłem na rozmowy z innymi programistami oraz przedstawicielami firm, mającymi swoje stanowiska (pobawiłem się też Kinectem ;) ). Okazało się, że mało kto wiedział gdzie leży Polska (wyjątkiem byli Europejczycy), a do tego wszyscy dziwili się co pehapowiec robi „behind enemy lines”. A na poważnie, to każdy zauważył pozytywną zmianę w kierunku rozwoju produktów webowych oferowanych przez Microsoft.

Podsumowując. Microsoft dostrzegł potencjał w młodych programistach i stara się ich przekonać do swoich produktów. Jednak zamiast niszczyć konkurencję, stara się stworzyć lepsze produkty. Mimo iż nie we wszystkich dziedzinach udało mu się dogonić resztę świata (IE9 mimo, iż dobry, raczej zamyka stawkę), to widać znaczącą poprawę. Kto wie, może za kilka lat, to PHP będzie musiał podbierać programistów Microsoftowi.

Korzystając z okazji chciałbym serdecznie podziękować Dariuszowi Piotrowskiemu, szefowi działu DPE polskiego oddziału Microsoftu oraz wszystkim osobom, dzięki którym mogłem pojechać na MIX-a.

Autor wpisu: batman, dodany: 18.03.2011 08:00, tagi: internet

W czasach, w których prawie każdy z nas nosi w kieszeni minikomputer, na popularności zyskują API pozwalające korzystać z najpopularniejszych aplikacji w prawie każdej sytuacji. Wystarczy wspomnieć o klientach Facebooka lub Twittera, które dostępne są na wszystkich znaczących platformach. Tworzenie klienckich aplikacji sprowadza się do wywoływania metod dostępnych w dostarczonych z daną usługą API.

Z pomocą w tworzeniu tego typu aplikacji przychodzi serwis apigee.com, oferujący międzyinnymi konsolę pozwalającą na testowanie komunikacji z wybranym API. Do dyspozycji mamy API takich serwisów jak Twitter, Facebook, Linkedin, czy PayPal.

Testowanie API to nie jedyna funkcjonalność jaką oferuje apigee. Serwis może udostępnić nasze API na świat zapewniając jego niezawodność oraz dostarczając statyki użycia.

Do poczytania/przetestowania:

Autor wpisu: batman, dodany: 15.03.2011 08:50, tagi: internet

Natknąłem się ostatnio na interesującą stronę, która pokazuje jak szybko/wolno ładuje się wskazana strona w różnych lokalizacjach naszego globu. Po wpisaniu adresu testowanej strony, wyborze lokalizacji oraz przeglądarki na jakiej chcemy ją przetestować, otrzymamy w wyniku ilość sekund po których nasza strona została wczytana. Poza samym czasem ładowania, możemy zapoznać się ze szczegółowymi informacjami dotyczącymi poszczególnych elementów naszej strony – odpowiednik zakładki Sieć znanej z Firebuga.

Strona znajduje się pod adresem http://loads.in/

Autor wpisu: Athlan, dodany: 10.01.2011 00:36, tagi: mysql, sql, internet

We wpisie Chmura tagów w PHP, w którym został przedstawiony problem budowy chmury tagów zapisałem przykładowe zapytanie prezentujące przykładowe dane dla klasy, które dosłownie zabija bazę danych zliczając za każdym razem ilość występowań tagów. Dostając feedbacki, zauważyłem, że problem ten jest bagatelizowany przez wiele osób. Spróbujmy zbudować bardziej optymalne rozwiązanie zarządzania strukturą danych w taki sposób, aby dane wyciągać bardzo bezboleśnie.

Zbudujmy przykładową strukturę bazy danych tagów, do której będziemy przypinać różne rzeczy – newsy, artykuły, galerie zdjęć, zdjęcia, cokolwiek.

Najprostsza tabela db_tags o polach:

  • tag_id, UNSIGNED, aby zwiększyć zakres INT – wartości ujemne nie są nam porzebne. Oczywiście primary key oraz auto increment.
  • tag_name, chociażby varchar(255)
  • tag_count, UNSIGNED, INT, ponownie bez znaku, aby zwiększyć zakres, wartości ujemne są nam niepotrzebne. Tutaj będziemy przechowywać liczbę reprezentującą, ile razy użyto tagu do oznaczenia dowolnego zestawu informacji.
CREATE TABLE db_tags (
  tag_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  tag_name VARCHAR(255) NOT NULL ,
  tag_count INT UNSIGNED NOT NULL
) ENGINE = INNODB;

Zastanówmy się, po czym będziemy sortować tagi. Warto założyć klucz na pole tag_count, znacznie przyspieszy późniejsze sortowanie wyników po najpopularniejszych tagach. Jeżeli chcemy sortować po liczbie występowań tagu oraz nazwie (aby chmura była alfabetycznie), warto założyć wspólny klucz na tag_name oraz tag_count. Osobiście sortowanie alfabetyczne zostawiam implementacji klasie tagów dla ksort(), bowiem zapytanie wyciągające tagi jest obarczone limitem, zatem wspólny klucz w bazie danych nie jest mi potrzebny – mniej danych w indeksach.

ALTER TABLE db_tags ADD INDEX (tag_count);

Tworzymy dowolną strukturę danych, która będzie podpinała się do naszych tagów. Pamiętajmy, że do tagów może podpinać się (a przynajmniej powinno, zależy od założeń początkowych projektu) wiele struktur jednocześnie. Wybrałem najbardziej pospolite – newsy w tabeli db_news.

CREATE TABLE db_news (
  news_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  news_title TEXT NOT NULL,
  news_content TEXT NOT NULL
) ENGINE = INNODB;

Pozostało nam stworzyć tabelę wiążącą nasze newsy z tagami (nie tagi z newsami). Tabelę nazwałem db_news_tags. Zawierać ona będzie tylko dwa pola przechowujące identyfikator newsa oraz przypisanego do niego tagu, zachowując typ danych wiążących, czyli INT UNSIGNED. Zakładam wspólny primary key dla obu pól.

  • handler_item – klucz ID newsa,
  • handler_node – klucz ID tagu.
CREATE TABLE db_news_tags (
  handler_item INT UNSIGNED NOT NULL,
  handler_node INT UNSIGNED NOT NULL,
PRIMARY KEY (handler_item, handler_node)
) ENGINE = INNODB;

Buduję relacyjną bazę danych. Gdy jakiś tag zostanie usunięty, bądź gdy jakiś news zostanie usunięty, automatycznie powinien zniknąć wpis z tabeli db_news_tags, zatem używamy kluczy obcych:

ALTER TABLE db_news_tags ADD FOREIGN KEY (handler_item) REFERENCES db_news (news_id) ON DELETE CASCADE;
ALTER TABLE db_news_tags ADD FOREIGN KEY (handler_node) REFERENCES db_tags (tag_id) ON DELETE CASCADE;

Tak zaprojektowaną strukturę danych mogę spokojnie używać do przechowywania danych. Pozostaje kwestia obliczania ilości występowań tagów. Istnieją co najmniej dwie szkoły.

  1. Każda zmiana danych w db_news_handler wywołuje procedurę liczącą tagi. Trzeba mieć na uwadze, że tagi są przeliczane od początku mielenie bazy, ale de facto proces odbywa się po kluczach. Zaletą rozwiązania jest to, że przy bardzo rozbudowanych strukturach (np. liczymy tylko aktywne i widoczne tagi) procedura uwspólnia nam warunki podliczania, używając jej w wielu miejscach nie musimy się martwić o redefiniowanie triggerów.
  2. Dla przedstawionego przykładu w tym poście wystarczy inkrementacja licznika przy dodaniu i dekrementacja przy usunięciu tagu. W większości przypadków właśnie takiego rozwiązania powinno się używać.

Luźny komentarz techniczny (problems, tips & tricks): Aby ominąć problemy wynikłe z założenia w punkcie pierwszym, równie dobrze możemy napisać procedury, które inkrementują/dekrementują liczbę tagów w zależności od warunków (np. tylko wtedy, kiedy tag jest aktywny i widoczny w serwisie). Nikt nie powiedział, że procedury muszą liczyć wszystko od początku możemy się na takie rozwiązanie zgodzić, rezygnujemy natomiast z synchronizacji licznika podczas zmiany warunków, wówczas podczas każdej zmiany warunków, trzeba przekręcić licznik od początku, zliczając wszystkie rekordy wg. ustalonych warunków ręcznie. Triggera należałoby również umieścić w UPDATE (zmiana stanu tagu, np. z niewidocznego na widoczny, z aktywnego na nieaktywny). I to jest najrozsądniejsze rozwiązanie.

W naszym przypadku ograniczymy się do dwóch triggerów, które będą trzymały rękę na pulsie w momencie przypisania tagu do struktury INSERT oraz zerwaniu przypisania DELETE. Zatem:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.