Projektowanie stron WWW od podszewki

Artykuły na każdy temat

[PHP] Zabezpieczenie typu antyflood (antiflood)

Dodano 16.07.2011r. o 00:55
Troszkę naszła mnie wena to pisze. Jakiś czas temu na forum pewna osoba zapytała mnie o rozwiązanie w tej sprawie. Powiedziała, że takich rzeczy nie ma necie. Skoro tak faktycznie jest to teraz jeden artykuł więcej będzie w tej materii. Dość dużo niedoświadczonych programistów nie zdaje sobie z tego sprawy, że takie zabezpieczenia są potrzebne. Chodzi głównie o to, aby ktoś nie spamował dajmy na to naszej skrzynki w przypadku, kiedy nie mamy innych zabezpieczeń typu captcha.

Cookies czyli ciasteczka

Najbanalniejsza metoda, jaka przyszła mi do głowy to są właśnie ciasteczka. W momencie dajmy na to wysłania wiadomości przeglądarka jest częstowana ciasteczkiem. W przypadku, kiedy ktoś chce wysłać wiadomość i ciasteczko nadal istnieje informujemy o tym petenta, że musi troszeczkę poczekać.
Kod:
<?php
$config['antyflood']['time'] = 30;
// Tutaj wyimaginowane części kodu

if($_COOKIE['send_message']) // Dla rygorystycznych drani mamy oczywiście isset()
{
 // Wiadomość do użytkownika, że musi troszeczkę poczekać
}
else
{
 if($message -> send(/* jakieś parametry */)) // Imitacja wysyłania wiadomości
 {
  // Mówimy użytkownikowi, że wysłał wiadomość i częstujemy przeglądarkę ciasteczkiem
  setcookie('send_message''bardzo_nieodpowiednia_treść'time() + $config['antyflood']['time']); // 30 sekund
 }
 else
 {
  // Mówimy użytkownikowi, że nie udało się wysłać wiadomości
 }
}
?>
Niestety ta metoda jest zawodna, bo część przeglądarek nie akceptuje ciastek bądź użytkownik nie życzy sobie tego papu.

Sesje

Lepszą formą zabezpieczenia są sesje jednak mają swoje wady, o których napisze poniżej listingu.
Kod:
<?php
$config['antyflood']['time'] = 30;

session_start(); // Żelazna zasada pracy z sesjami

// Usuwamy, jeżeli jest taka potrzeba
if($_SESSION['send_message'] && (time() - $_SESSION['send_message']) > $config['antyflood']['time']// Dla rygorystycznych draniu mamy oczywiście isset()
{
 unset($_SESSION['send_message']);
}

// Tutaj wyimaginowane części kodu

if(!$_SESSION['send_message'])
{
 if($message -> send(/* jakieś parametry */)) // Imitacja wysyłania wiadomości
 {
  // Mówimy użytkownikowi, że wysłał wiadomość i ładujemy informacje do sesji
  $_SESSION['send_message'] = time();
 }
 else
 {
  // Mówimy użytkownikowi, że nie udało się wysłać wiadomości
 }
}
else
{
 // Wiadomość do użytkownika, że musi troszeczkę poczekać
}
?>
Problem polega na tym, że przeglądarka niekoniecznie musi zaakceptować ciastko z SID. W takim przypadku zostaje przekazywany w url'u, który tez nie musi zostać zaakceptowany to znaczy nie musi zostać przekazany identyfikator do kolejnej strony. W takim przypadku zabezpieczenie staje się całkowicie bezużyteczne.

Zapisywanie IP

Moim zdaniem najbardziej efektywna metoda, bo zmiana IP trwa chwilkę i natrętowi może w tym czasie się znudzi resetować router czy co tam ma. Skrypt działa w ten sposób, ze tworzy plik, którego nazwą jest IP w formacie liczby. Operujemy na dacie pliku więc nie trzeba się bawić nawet w otwieranie w najprostszym wydaniu tego skryptu. Oczywiście można to rozbudować ale...
Kod:
<?php
$config['dir']['antyflood'] = './antyflood/';
$config['antyflood']['time'] = 30;

$ip ip2long($_SERVER['REMOTE_ADDR']); // Jakaś metoda bądź funkcja do pobierania IP
$path $config['dir']['antyflood'].$ip;

if(file_exists($path))
{
 // Niekoniecznie trzeba usuwać, może wystarczyć update daty pliku (ale moim zdaniem lepiej usuwać)
 if(time() - filemtime($path) > $config['antyflood']['time'])
 {
  unlink($path);
 }
 else
 {
  $catch true;
 }
}

if($catch)
{
 // Wiadomość do użytkownika, że musi troszeczkę poczekać
}
else
{
 if($message -> send(/* jakieś parametry */)) // Imitacja wysyłania wiadomości
 {
  // Mówimy użytkownikowi, że wysłał wiadomość i zapisujemy jego IP
  touch($path); // Mogą być inne funkcje
 }
 else
 {
  // Mówimy użytkownikowi, że nie udało się wysłać wiadomości
 }
}
?>
I teraz potrzebny worker, bo za każdym wywołaniem skryptu nie będziemy czyścić plików outdated. Najlepiej odpalić taki skrypt z poziomu CRON'a i nie martwic się, że folder z takimi danymi zostanie zasypany.
Kod:
<?php
$config['dir']['antyflood'] = './antyflood/';
$config['antyflood']['time'] = 30;

$list glob($config['dir']['antyflood'].'*');

if(!empty($list))
{
 foreach($list as $file)
 {
  if(time() - filemtime($file) > $config['antyflood']['time'])
  {
   unlink($file);
  }
 }
}
?>
Cala sytuacja tyczy się gości, którzy nie maja możliwości rejestracji. Naturalnie rejestracja może ograniczać, ale co z multikontami? W takich wypadkach metoda IP konieczna. Oczywiście można stworzyć do tego klasę, ale to pozostawiam Waszej inwencji twórczej. Podsumowując powiem, że połączenie tych trzech metod może dać wymierne korzyści.

Komentarze

Publikowane komentarze są prywatnymi opiniami użytkowników serwisu. Serwis nie ponosi odpowiedzialności za treść opinii. W trosce o zachowanie poziomu dyskusji wszystkie komentarze podlegają akceptacji przed ich publikacją dlatego proszę cierpliwie czekać aż komentarz zostanie opublikowany.

Rasmus

Dodano 01.10.2015r. o 11:22
Użytkowniku @Pawl zanim podasz kontrowersyjne rozwiązanie radzę zapoznać się z tym i tym materiałem. Zagrożenia płynące z wykorzystywania tzw. evercookie są ogromne.

CapaciousCore

Dodano 26.09.2015r. o 16:35
@Pawl Nie zgadzam się z Tobą. Skoro ktoś z Twojej sieci przez swoją głupotę zablokował dostęp innym to jest to jego problem. W akademikach jest wiele tzw. wyjściowych IP to po pierwsze. Po drugie istnieje coś takiego jak proxy. A po trzecie każde "zabezpieczenie" lub pseudo rozwiązanie pokroju overcookie idzie obejść. Gdyby to było takie dobre to wszystkie hostingi plików by stosowały bez umiaru, a dobrze wiesz o tym, że tak nie jest.

Pawl

Dodano 04.02.2015r. o 14:57
Okropny pomysł Smile Ja sam mam w domu 5 komputerów - 5 osób. Jeśli ja zablokuję czymś dostęp to blokuję go nie tylko sobie, ale także wszystkim, którzy mają to samo IP. A piszę tutaj o mieszkaniu, a weźmy np. taki akademik, gdzie każdy jedzie na tym samym IP.

Rozwiązanie: Overcookie.

CapaciousCore

Dodano 13.02.2013r. o 08:36
A dlaczego miałbym to robić? Takie działania można przypisywać najwyżej do gamoni powiązanych z zabiegami SEO i zapleczami. Czy ja na takiego wyglądam? Chyba nie...

Krzysztof Baraniak

Dodano 12.02.2013r. o 00:48
Twoje komentarze są świetnie, widać że nie kopiujesz skryptów z google'a. Smile

Luk

Dodano 16.01.2013r. o 15:55
Super! Dzięki za pomoc - bardzo skorzystałem. Pozdrawiam.

CapaciousCore

Dodano 10.02.2012r. o 21:07
@Gosc Metodę send() traktuj jako metaforę. Czyli jeżeli udała się jakaś akcja to wtedy zapisz informację o niej.

Co do metody z ciasteczkami to polecam zapoznać się z evercookie.

Gdzieś kiedyś mówiłem, że ten skrypt można rozbudować, czyli np. dla konkretnych eventów (zdarzeń) przypisywać zapisywanie tych informacji na serwerze. No ale osoba zaawansowana dojdzie do tego co i jak.

Gosc

Dodano 10.02.2012r. o 17:44
A co dokładnie masz na myśli pisząc, żeby podać parametry przy send().

CapaciousCore

Dodano 06.09.2011r. o 19:50
@obelix94 jeżeli ktoś często przegina limity czasowe to można temporarily ban dawać. Np. pobiera stronę i szybciej ją wypełnia niż to możliwe to blokada albo preparacja sztucznej strony dla niego. Chce zauważyć, że to tylko jedno z rozwiązań antyspamowych. Zauważ, że to artykuł na temat antyflood, a nie zabezpieczę antybotowych. Co do tych ciastek to wiem o tym i postaram się jak najszybciej.

obelix94

Dodano 05.09.2011r. o 20:52
Dzięki, przyda mi się. A co do komentarzy: zapisuj w cookie podpis, email i stronę www żebym za każdym razem nie musiał tego wpisywać.

obelix94

Dodano 05.09.2011r. o 20:49
Spoko artykuł. Myślę jednak, żę gdy wbije nam na serwer jakiś bot, to to nic nie da ;) Sprawdzi się to tylko przed "humanami"

Dodaj komentarz

Zostaw komentarz jeżeli możesz! Nie bądź przysłowiowym botem! Nie bądź obojętny! Ciebie to nic nie kosztuje, a mi sprawi uśmiech na twarzy.
Zezwolono używać: BBCode
Zabroniono używać:
znaczników HTML

(Wymagany)

(Wymagany, niepublikowany)

(Nie wymagana)

Token:

Obrazek dla bota

(Przepisz tylko cyfry!)

(Wymagana)