Automatyczne wykrywanie spamu na Blox.

Trochę z rozpędu po ostatnim spojrzeniu na beznadziejną captchę na Blox, trochę zażenowany brakiem działania administratorów Blox w tak wydawałoby się prostej sprawie, trochę chcąc odkurzyć stare skrypty i znajomość Perla, trochę ze względu na zainteresowaniem tematem spamu, a w końcu trochę dla zabawy, postanowiłem zrobić przymiarkę do automatycznego wykrywania spamu na Blox. Chodzi o określanie, czy dany blog służy wyłącznie spamowaniu, oczywiście automatycznie, a co za tym idzie nie ze stuprocentową pewnością.

Administratorzy zapowiedzieli, że captcha zostanie poprawiona w kwietniu (trzymam za słowo i liczę na to, zapewne nie tylko ja), więc spamblogów nie powinno od tej pory przybywać. Zatem postanowiłem skupić się nie na liście nowozałożonych blogów, tylko na liście nowych wpisów, czyli aktywnych spamblogach. Co prawda pierwotny plan zakładał przeiterowanie się po wszystkich blogach i określenie prawdopodobieństwa, czy jest to spamblog, ale nie znalazłem niestety listy wszystkich blogów na Blox. Owszem, można próbować robić rzeźbę pod tytułem „przeiterujmy się po tagach”, ale nadal nie daje to gwarancji uzyskania listy wszystkich blogów – wystarczy, że ktoś nie taguje i system nie dotrze do jego bloga, więc stanęło na tym, że obserwuję listę nowych wpisów i stamtąd biorę dane. Przy okazji oceniam nie tyle cały blog, co poszczególne wpisy, co może być przydatne.

Podejście pierwsze – pobierz i oceń. Na samym początku stwierdziłem, że będę pobierał wpis do oceny i oceniał na podstawie arbitralnych kryteriów. Pomysł szybko upadł – zmiany w algorytmie oceniania powodowały niekompatybilność z poprzednimi danymi, a zmiany były konieczne – wychodziły coraz to nowe kryteria i ich wagi. Wersjonowanie algorytmu przy ocenie nie pomagało, bo dane były tracone. OK, nie jest to wszystko aż tak proste, jak się wydawało na początku.

Podejście drugie – pobierz i zapisz jak najwięcej cech wyróżniających dla danego wpisu/bloga, a potem pomyśli się nad algorytmem. No niestety, zapisywanie dużej ilości danych może być ciekawe, szczególnie, że potem można sięgnąć do wiedzy ze studiów i określić poziomy istotności poszczególnych parametrów (albo popytać kumpla o gotowca, może jeszcze ma…). Wytrenuje się AI na próbce kontrolnej, a potem AI sama zrobi resztę. Brzmi fajnie, ale trochę overkill, poza tym, mało odporne na dołożenie kolejnych parametrów, gdyby przyszło mi do głowy ich wyciąganie.

Podejście trzecie, aktualne,kompromisowe – pobierz i zapisz istotne (wybrane arbitralnie przeze mnie) cechy wyróżniające dany wpis. Osobny skrypt ma algorytm procentowy, każda cecha może przyjmować wartości 0-100% prawdopodobieństwa bycia spamem. Następnie w zależności od ilości cech wylicz prawdopodobieństwo dla całego wpisu przy pomocy średniej ważonej. Rezultaty są dość interesujące.

Tutaj lista blogów (praktycznie nikt nie korzystał, więc wywaliłem), które sklasyfikowałem jako spamerskie z prawdopodobieństwem 80% i więcej. Format prawdopodobieństwo bycia spamem (%), spacja, link do bloga. Nie widzę (szybko patrząc) żadnego false positive, a wy? Aktualnie jest takich blogów 375 na 2404 wszystkich sprawdzonych blogów. Jasne, nie jest to cud techniki, ale przy dodaniu pewnych prostych whitelist myślę, że można spokojnie blokować automatem wszystkie blogi z prawdopodobieństwem od 70% w górę.

Szczegółów badanych cech oraz algorytmu nie chcę na razie opisywać, bo po co spamerzy mają się bronić? Jak będzie utrudnione zakładanie nowych blogów, to pomyślę o tym. Na razie cały czas zbierają się dane… Gdyby byli chętni do przeglądania wyniku w celu wychwytywania false positive’ów (wpisujcie miasta, które przeglądają ;-)), to mogę pomyśleć o wystawianiu listy spamów automatem co jakiś czas.

Całość napisana oczywiście w Perlu, główny moduł zbierający z użyciem WWW::Mechanize (genialna sprawa do crawlerów).

UPDATE: Drobny update statystyk z dnia 27.04.2012 – 13481 unikatowe blogi (wcześniej chyba były unikatowe wpisy, ale mniejsza), w tym 1094 do natychmiastowego wycięcia (80% i więcej). Dla porządku 70% i więcej to 2438 sztuki. Listy nie zamieszczam, bo zainteresowanie było znikome. A captcha nadal nie została poprawiona, choć koniec kwietnia…

Spam na Blox, czyli jak nie implementować CAPTCHA.

Od dłuższego czasu serwis blogowy Blox boryka się z plagą spamu. Słyszałem zapewnienia, że moderatorzy/admini walczą z tym zjawiskiem, ale wydaje mi się, że bez większych sukcesów, a nawet, że problem spamu się nasila. Jest to zjawisko dla wszystkich (poza spamerami) niekorzystne, a nierzadko na stronie głównej o pewnych porach spamy stanowią 30 i więcej procent wpisów.

Postanowiłem zerknąć na proces zakładania konta od początku. Pierwsze co rzuciło mi się w oczy, to prostota CAPTCHA. Być może parę lat temu wystarczało coś takiego, by odstraszyć spamerów, ale wojna trwa – istnieją narzędzia do automatycznego rozpoznawania nawet dość skomplikowanych CAPTCHA ze stosunkowo dużą pewnością (grubo ponad 50%). Niedawno nawet Jogger, który pozwalał właścicielowi bloga na mocne zmiany wyglądu CAPTCHA (kształt, wielkość, kolor), przy komentarzach dorzucił do niej litery obok cyfr, bo spamerzy się przebijali…

Żeby sprawdzić, czy nie przypadek, że CAPTCHA jest taka słaba, wcisnąłem F5, raz, drugi, trzeci… I okazało się, że trafiłem na powtarzające się słowa. Chwilę się pobawiłem i faktycznie, nie da się ukryć, CAPTCHA powtarza się i to – na oko – często. Postanowiłem sprawę zbadać dokładniej.

Sposób badania: uruchomienie przeglądarki, wyczyszczenie historii, w każdej serii 50 przeładowań strony (F5 lub ctrl-r), zapisanie wyników do pliku (każdy wynik w pojedynczej linii) w takiej kolejności, w jakiej się pojawiały. Żeby wykluczyć wpływ User Agent i czasu, każda seria wykonywana na różnej przeglądarce i w odstępie minimum kilkudziesięciu minut.

W pierwszej serii (przeglądarka chromium) 50 ciągów wyrazów wystąpiły 32 unikatowe ciągi, przy czym 4 wystąpiły trzykrotnie, 10 dwukrotnie, a 18 tylko raz. Dodatkowo rzuciła mi się w oczy prawdopodobna metoda powstawania wielu CAPTCHA – podział słowa na sylaby, połączone z ew. wyrzuceniem niektórych liter, a następnie wymieszanie tych slab. Przykładowo zykamu i kazymu (czyli muzyka), letefon, fontele i fonlete (czyli telefon), zetagagataze (czyli gazeta), lafiorka, fiorkala, fiorlaka (czyli kalafior).

Druga seria, kilkadziesiąt minut później na midori – 34 unikatowe ciągi, jeden wystąpił czterokrotnie, 13 dwukrotnie, 20 jednokrotnie. Wyrazy zdecydowanie powtarzają się między seriami – dla obu serii łącznie wystąpiło 46 unikatowych ciągów, 2 wystąpiły pięciokrotnie, 6 – czterokrotnie, 8 – trzykrotnie, 12 -dwukrotnie, 18 – jednokrotnie.

Ponieważ ciąg znaków pod którym można poprać losowany obrazek może być stały (z danego można korzystać wiele razy), postanowiłem uprościć sobie pobieranie i przeliczanie. Szybki skrypt, który przy pomocy wget pobiera zadaną ilość obrazków i zapisuje do kolejnych plików, a następnie sprawdzenie sum kontrolnych (md5) tychże plików. I tu ciekawostka – sumy kontrolne praktycznie się nie powtarzają. Sprawdziłem organoleptycznie i faktycznie – o ile wyrazy powtarzają się często, to praktycznie każdy plik jest binarnie inny. Czyli raczej mała ilość wyrazów raczej nie wynika z chęci cache’owania.

Dla porządku: dla 100 plików 3 miały takie same sumy kontrolne, a kolejne 5 sum występowało dwa razy. Powtórzyłem eksperyment dla 1000 plików. Pojawiło się 611 unikatowych sum kontrolnych, jedna z sum występowała 7 razy, jedna 6, sześć wystąpiło 5 razy, cztery – 20 razy, trzy – 53 razy, dwie – 188 razy i jedna – 342 razy.

Nie sprawdzałem dokładnie, czy dany wyraz w CAPTCHA koreluje z ciągiem w treści (na oko nie), ani z jaką skutecznością zadziała automatyczne rozpoznawanie, ale przy tak częstym powtarzaniu się ciągów znaków i plików nie ma to znaczenia – wygląda, że baza jest za mała, a przekształcenie zbyt proste i można spokojnie stworzyć skrypt, który porówna sumę md5 wygenerowanego pliku z arbitralną bazą.

O problemie pisałem wstępnie na forum, póki co bez odzewu. W każdym razie liczę na to, że wpis zmotywuje administratorów blox do załatania ewidentnej dziury w zakładaniu nowych kont. Obecne likwidowanie spamerskich blogów przypomina wylewanie wody z łódki, zamiast załatania w niej dziury, przez którą wody nabiera.

Oczywiście najlepsze byłoby podpięcie jakiegoś znanej, sprawdzonej implementacji CAPTCHA, zamiast wymyślania koła od nowa (i to sugestia dla tych, którzy chcą stosować tego typu rozwiązanie) ale wydaje się, że nawet z istniejącą implementacją można prosto zadziałać w taki sposób, że stanie się ona choć w części efektywna. Przede wszystkim mam na myśli zwiększenie bazy słów i ilości przekształceń.

Obok złych wiadomości są też i dobre – co prawda problem nie jest to Blox, tylko ogólnie dotyczy konto.gazeta.pl, ale – jak wynika z korespondencji z administratorami Blox – jest znany i ma być najdalej w kwietniu poprawiony. Pozostaje uzbroić się w odrobinę cierpliwości i liczyć na to, że po załataniu dziury uda się skutecznie pozbyć spamerów. W tej chwili bywa tak, że 100% wpisów na głównej stanowią spamy…

Krytyczny rzut oka na doLoop.

Na informację o serwisie doLoop natknąłem się podczas lektury bloga o najlepszych dodatkach do blogów. W skrócie jest to wymiana ruchu – ja linkuję kogoś, ktoś linkuje mnie. Z grubsza tematycznie, tzn. można wybrać, jaką tematykę chcemy linkować i określamy kategorię tematyczną własnych wpisów. Postanowiłem wypróbować, jak to działa i co to daje.

Zaczęło się niezbyt dobrze. Po pierwsze, na stronie serwisu doLoop (obecnie 404) nie ma regulaminu (AKA ToS). Jest FAQ, które coś tam wyjaśnia, ale normalnego regulaminu nie ma. Niefajnie, bo nie musi być nie wiadomo co, ale wystarczyłoby w kilku punktach opisać warunki korzystania z serwisu.

Po drugie, zamieszczanie linka w serwisie jest całkowicie ręczne. Po prostu trzeba wklepać linka, opis, tagi. Wszystko ręcznie, bez możliwości skorzystania z automatów typu javascript i zamieszczenia danych typu tytuł czy tagi automatycznie (OK, tytuł może zaciągnąć automagicznie z URLa). Co przecież jest jak najbardziej wykonalne – Folksr to potrafi. Marnym pocieszeniem – przynajmniej dla mnie – jest możliwość dodania kanału RSS i wybierania postów do dodania z niego.

Na dodatek wymagane jest dodanie zdjęcia. Po prostu i zwyczajnie nie da się zamieścić wpisu bez zdjęcia. Na dodatek zdjęcie musi pasować do treści. W praktyce pewnie czeka mnie szukanie jakichś zdjęć na licencji Creative Commons, albo – raczej – public domain, bo CC wymaga podania autora o co trudno w tej sytuacji. Za robieniem własnych fotek/zrzutów nie przepadam. Nawet do wpisów, co dopiero do zajawek o wpisach.

Po trzecie, mail z potwierdzeniem odbioru prośby rejestracji, który przyszedł, miał skopane pl-znaki w temacie, co wygląda delikatnie mówiąc mało profesjonalnie. Mail z potwierdzeniem dodania do serwisu, który dotarł po około 12 godzinach – to samo. No ale skoro dobrnęliśmy do tego momentu, to kontynuujmy…

Pozytywem jest bardzo dużo opcji wyglądu widgetu. Powiedziałbym nawet, że za dużo i chyba wolałbym podział na widok podstawowy i zaawansowany. Ale domyślne ustawienia praktycznie nie wymagały korekty (no dobrze, rozmiar zdjęć zmieniłem, ale to podstawa).

Testowe zamieszczenie pierwszego wpisu – wypełnianie ręczne dla pojedynczego jest niby do przeżycia, ale na dłuższą metę będzie męczące jak dla mnie – m. in. dlatego nie korzystam z Wykopu czy nie dodaję wpisów do katalogu Flattr. Bardzo fajną rzeczą jest możliwość podania linka do zdjęcia, a następnie prostego wykadrowania i – w razie potrzeby – pomniejszenia w przeglądarce. Przynajmniej nie trzeba uruchamiać edytora grafiki.

Za to czas moderacji wpisu to jakiś koszmar – rozumiem, że jest robione ręcznie i uprzedzają w FAQ moderacja postów trwa przeważnie do 12 godzin, ale kilkadziesiąt godzin to trochę przesada. Przynajmniej na początku drażni, kiedy się czeka na efekty, potem nie przeszkadza w ogóle – przestałem zwracać uwagę na czas moderacji.

Inne niefajne rzeczy:

  • Po zgłoszeniu błędu zero informacji o przyjęciu, zero informacji, czy będzie naprawiany i kiedy.
  • Błędy ortograficzne – po dodaniu do czarnej listy proszę odświerzyć stronę.
  • Mimo zaznaczenia przy zakładaniu konta, żeby „atrakcyjnych dziewczyn” nie pokazywało i wyłączania kategorii Sexy, zdarzają się praktycznie gołe dupy na zdjęciach. Znaczy w stringach. Można to oczywiście blokować blacklistą, ale jakby nie takie jest założenie. I niestety nie można zablokować konkretnego wydawcy w całości.
  • Problemy z pl-znakami – występują i w mailach, i przy pobieraniu danych o tytule wpisu. To pierwsze to wina doLoop, to drugie może być winą Blox i archaicznego kodowania pl-znaków.

Nie miałem przypadku, by dodawany wpis został odrzucony, za to męczące jest ograniczenie w dodawaniu wpisów – w praktyce mogłem dodawać po jednym wpisie dziennie – przypuszczam, że chodzi o swoiste zabezpieczenie antyspamowe. Rozrzut CTR (stosunek wyświetleń reklamy danego posta do wejść) mam spory, bo od ok. 1,3% (beznadziejne zdjęcie) do ok 20% (świeży wpis, CTR spada z czasem).

Wyniki, czyli część najważniejsza, bo widget dodaje się w celu zwiększenia ruchu na stronie (albo przyciągnięcia nowych czytelników, jak w moim przypadku). W FAQ piszą przeważnie można liczyć na od 150% do 200% zwiększenia ruchu na twojej stronie po zainstalowaniu widgetu doLoop. Na mój gust o zero za dużo, przynajmniej na tym blogu. 20% jest za to jak najbardziej osiągalne. Wiele zależy od dodanych wpisów – liczy się i opis (tu nie szalałem, po prostu tytuł z bloga), i zdjęcie. W testowym okresie, wynoszącym 14 dni, unikalne wejścia z doLoop stanowiły ok. 15% wszystkich UU.

Ogólne zadowolenie – 4/10, na razie zostawiam to, co jest, zobaczę jak będzie wyglądało w dłuższym okresie (będzie aktualizacja statystyk). I rozglądam się za alternatywami.

UPDATE: No i jednak doLoop okazał się happeningiem, jak wskazywały na to niektóre rzeczy typu brak ToS czy orty. Od paru dni(!!!) strona główna pokazuje Błąd bazy danych!! Znaczy się do piachu.