Ochrana formulářů proti spamu

Školení, která pořádám

Pokud je na stránkách formulář, který slouží pro odesílání informací e-mailem, je potřeba ho zabezpečit proti e-mailovému spamu. Pokud se text z formuláře někde zobrazuje, je oblíbeným terčem tzv. komentářových spamerů. Ti spamují proto, aby se na webu objevil odkaz na jejich stránky. Pokud bude odkaz aktivní a zvýší jim tedy PageRank, tím lépe, ale spokojí se i s prostým zobrazením odkazu, který si třeba také někdo ručně otevře. Proto je neodradí zvýrazňování odkazů s využitím rel="nofollow", jejich nezvýrazňování, ani dodatečné mazání těchto komentářů a je potřeba se proti nim bránit jinak. Jednu primitivní metodu ochrany formulářů proti komentářovému spamu už jsem ukazoval, doba nicméně pokročila, spameři se zdokonalili a jednoduché metody obrany už nezabírají. Mezi ty mohlo patřit schválení příspěvku po přesměrování ze stránky pro uložení, generování náhodného řetězce a jeho ukládání do session proměnné nebo kontrola příliš rychlého nebo naopak pomalého odeslání formuláře.

V současnosti je asi nejoblíbenější chtít po uživateli zadat odpověď na jednoduchou otázku a protože se roboti ještě nenaučili zpracovat JavaScript, tak tuto odpověď za uživatele automaticky vyplnit a otázku skrýt. Skrývání se obvykle dělá pomocí stylu, jednodušší na vytvoření a použitelnější pro lidi s vypnutými styly je ale využít značku <noscript>:

<noscript><p>Vyplňte nospam: <input name="robot" size="6" /></p></noscript>
<script type="text/javascript">
document.write('<input type="hidden" name="robot" value="no' + 'spam" />');
</script>

Před uložením formuláře pak stačí ověřit hodnotu formulářového pole robot. Otázka samozřejmě může být složitější nebo pro každého uživatele jiná, např. nějaká početní operace, princip ale zůstává stejný.

Touto metodou se dá proti současným robotům efektivně bránit a plnohodnotná obrázková CAPTCHA by tak byla potřeba pouze v případě, kdy by se naše stránky stávaly cílem specializovaného útoku. Ale je potřeba pamatovat na to, že i řada obrázků se dá přečíst automaticky.

Jakub Vrána, Řešení problému, 8.9.2006, diskuse: 69 (nové: 0)

Diskuse

kahi:

Milý článek, zvlášť když jsem řešení stejného problému věnoval předchozí hodinu, a výsledkem bylo řešení podobné Vašemu, jen o poznání méně elegantní. Přesto díky :-).

ikona dgx:

Rozhodně doporučuji pole nenazývat "robot", ale nejlépe třeba "email".

Pavel:

Díky určitě využiju, protože doteď tam mám ať uživatel napíši nějakou číslici 0-9, ale tohle se mi zda alegantnější. Díky

Pachollini:

Osobně se mi osvědčil keyword blacklist. Nejúčinnější pro filtrování se mi jeví "<a href=" a "[url". Lidi takovou pitomost do formuláře, který to evidnentě nepodporuje, nikdy nenapíšou.

ikona Jakub Vrána OpenID:

Problém je v tom, že roboti obvykle zkouší i zadání prostého URL bez jakýchkoliv značek.

Peter:

Ja som to tak odfiltroval a spam chodi stale .. uz nie s www adresami ale s obycajnym sprostym textom ...

rony:

ja doporucujem zamerat sa aj na TAG FORM. Akonahle ho skryjes, tak robot ho nevidi a ani sa nepokusa odosielat formularove data.

adrive:

Môžeš dať príklad, ako tag form skryť? Či obdobným trikom noscript, script, document.write?

mrzout:

Nevim jestli to tak bylo puvodne zamysleno, ale ...

Samotny FORM by mohl byt do stranek pridan javascriptem ci Ajaxem ->coz ovsem odstrihne od moznosti prispivat vsem, kdo ho ma vypnut.

adrive:

no akonahle by bol form skrytý takýmto spôsobom, bolo by to vsetko jedno. pretoze v tagoch noscript by bol daný "odkrytý"

Kája:

Tak mrzout tuším na značku noscript nějak nemyslel, spíš zavedl něco jako nulovou toleranci k uživatelům vypínajících JavaScript. :-)

ikona Jakub Vrána OpenID:

Pro fanoušky norem by se slušelo zmínit ještě dvě věci. Čekal jsem, až to někdo nakousne v komentářích, ale zatím se nikdo neozval...

1. V XHTML se nemá používat document.write(): http://www.w3.org/MarkUp/2004/xhtml-faq#docwrite. Jako náhradu lze použít document.createElement() a následné appendChild().

2. Vnitřek značky <script> by měl být kvůli zpětné kompatibilitě uzavřen do HTML komentářů (http://www.w3.org/TR/html4/interact/scripts.html#h-18.3.2), ty ale čisté XML parsery mohou zahazovat (http://www.w3.org/TR/xhtml1/#C_4), proto je lepší značku <script> používat výhradně s atributem src.

taui:

tohle se dela uplne bezne a myslim ze s tim neni problem:/*<![CDATA[*/

ikona Jakub Vrána OpenID:

Čistě teoreticky by s tím měly problém prohlížeče, které neznají značku <script>. Ty by měly vnitřek značky zobrazit jako prostý text, proto se zavedlo obalování vnitřku značky do HTML komentářů, které ale XML parsery mohou vyřadit ještě před zpracováním stromu značek.

Ale vzhledem k tomu, že se takové prohlížeče dnes už nepoužívají, tak se jedná o čistě teoretický problém.

uzivatel:

Ja to riesim tiez obdobne pomocou javascriptu.
Mozno to niekto pouzije a mozno nie.

Vytvorim klasicke dva inputy s opisovanim cisla. Ale avsak ma navstevnik povoleny javascript tak pomocou getElementById opisem cislo z jedneho inputu a vlozim ho do druheho.
Tieto dva inputy mam ohranicene v nejakom dive a poslednou castou javascriptu mu definujem display:none a tym padom nie je vidiet.

Ludom s vypnutym javascriptom sa tento opisovaci formular zobrazi.

ikona Jakub Vrána OpenID:

Pokud má někdo vypnuté styly, tak se mu políčko neskryje. V tom je mnou popsané řešení lepší.

uzivatel:

Ano to chapem, ale ktory blazon si vypina styly ? Javascript este chapem, lebo vela ludi je z neho vyklepanych pretoze ho nechapu a len nieco poculi tak to vypinaju. Lebo to je asi moderne ci co to :)

Ale ked niekto vypne styly tak je jedno ci tam bude mat o dva inputy viac ked bude mat cely rozsypany vzhlad ;)

A len tak z jemneho kutika. document.write je tak jednoducha funkcia, ktoru sa mozu SPAMovacie stroje naucit lahko. Kdezto vytahovanie hodnoty, vkladanie hodnoty a ine veci im bude trvat dlhsie, odhliadnut od toho, ze sa moze pouzit dlhsi javascriptovi kod s viacerymi postupmi, ktory nakoniec bude robit to iste ako jeden riadok a je takmer postarane o spam, pretoze pochybujem, ze by stroje v dohladnej dobe vedeli pracovat s viacerymi prvkami javascriptu.

Avsak Vase riesenie je fakt elegantne.

Marek:

podle mne, pokud se autori spambotu nastvou a rozhodnou se vyzrat na javascriptove antispamy, tak proste vykradou z nejakeho opensource projektu plnohodnotny javascriptovy interpreter (gecko od mozilly napriklad) a razem bude uplne jedno jestli pro vkladani pouzivate insertnode nebo document.write :-)

Shalafi:

Nejde ani tak o to,ze by si nekdo umyslne vypinal styly, jde spis o to, ze nektere specialni prohlizece je nemusi interpretovat (pr.:prohlizece pro slabozrake)

roman:

Mne sa momentalne osvedcilo zakazat odkazy na ine stranky. Vychadzal som z toho ze vsetky spamy obsahuju odkaz, tak ked prispevok obsahuje htttp alebo www tak sa jednoducho nezapise.

Trochu tvrde riesenie, ale na webe kde som to pouzil bolo 99% odkazov bez URL. Keby bolo treba tak dorobim CAPTCHA na zapisanie prispevku, ktory obsahuje URL. Radsej obtazovat par uzivatelov ktori chcu napisat URL ako vsetkych.

ikona Jakub Vrána OpenID:

Zakázat všechny příspěvky s URL je v naprosté většině diskusí příliš restriktivní.

Nejlepší je s vyplňováním CAPTCHA neotravovat nikoho, to přesně toto řešení nabízí (pokud má uživatel zapnutý JS).

roman:

Ano, je to restriktivne, ale v tom pripade to nevadilo (je to nieco ako faq)

Hooonza:

No, odkazy se nemusejí filtrovat všechny, stačí např. omezit jejich počet (např. na 4). I když na to mi teď nějaký spammer přišel:-)

Michal:

Opravdu nechápu tu neustálou naivitu... to si fakt všichni myslíte, spamboti brzy nezvládnou javascript? Spoléhat na to, že roboti javascript neumí, je odkopnutí hovna metr před sebe. Pardon.

ikona Jakub Vrána OpenID:

Navrhni tedy prosím lepší řešení, které odstřihne roboty, nebude obtěžovat uživatele a bude trvale platné.

piler:

ja som siel na to z ineho konca...

spravit input, ktory sa nesmie vyplnit, cize do neho nesmie byt nic napisane. aby to uzivatela neotravovalo, tak sa to schova stylmi. Neviem presne na kolko % to bude funkcne, ale mam pocit, ze roboty sa snazia vypnit kazde policko.

uzivatel:

Tento napad vyzera zaujimavo

insekticid:

Jenze kdyz mu das type="hidden" robot ho vyplnovat nebude. (proc by totaky delal kdyz ho uzivatel nemuze videt)

A podle me nemuze byt problem do roBota napsat kontrolu pro  style="display:none" -> aby tento input ignoroval. hm?

piler:

zakazal by som to cez css, nie inline stylmi

<input type="text" name="nevyplnma" value="" class="nevyplnma" />

Marek:

... to uz mas prece uplne jedno. Ten spambot pokud bude pouzivat nejaky plnohodnotny parser a interpreter javascriptu (jadro gecko napriklad) , tak se ta css vlastnost k tomu elemtentu dostane nakonec tak jako tak, a je ji mozne na jeho urovni zdetekovat stejne dobre, jako by byla inline

Marek:

Jak ja to vidim, tak vsechny ucinne pasivni (nevyzadujici vstup od uzivatele) antispamove triky spolehaji jen na to ze spambot neco neumi interpretovat, zatimco internetovy prohlizec uzivatele ano ... sazime na to ze neumi javascript (je to otevreny standard, opensource interpretu je vice nez dost, tohle neni sazka na jistotu), sazime na to ze neodhali pole skryte pomoci css (pche, totez co v pripade JS, tohle se nauci raz dva) ... co takhle vsadit na uzavrenou technologii, kterou se jen tak nenauci ? Macromedia FLASH !!! :-), ja vim, ted asi zvedate oboci (v lepsim pripade), ale zvazte to. To ten ubohy blackbox "Macromedia FLASH plugin" vlastne programatorovi spambota umoznuje ... skoro nic. Nemuze poradne vyhodnotit jeho obsah, nemuze s nim nijak zvlast komunikovat ... proste pokud si ve flashi vytvorite cely formular pro odeslani prizpevku i s tlacitkem submit, ma spamer smulu :-) Do tohoto blackboxu proste nepronikne.

Marek:

Hmmm, tak to beru zpet ... tak nejak se spozdenim mi doslo, ze i kdyby flash (evetualne java) umoznila pripojit se primo k databazi a do ni vlozit ziskana data, patrne by se dalo na trase odposlouchat jmeno a heslo pro vstup k databazi :-)))) , a to by jiste veci neprospelo. Tak nic.

Prasisko:

Tuto metodu jsem zkoušel, ale spamboti už nejspíš objevili význam obalovacího <div style="display:none;"> a nic mi tam nepíšou... i když se ta políčka jmenují lákavě jako třeba "link", "www", "home", "mail" atd.

Shalafi:

Nefunguje - ted mi to ty mrchy o*cavaj.

Kája:

To máš těžky, sice se ho pravděpodobně naučí, zvlášť pokud se řešení na něm založené rozšíří, tak je to z tohoto hlediska trochu krátkozraké, ale na druhou stranu, nikdo neříká, že to nelze použít jen jako doplňkovou techniku. Hlavně bych ale zdůraznil, že zatím je toto řešení účinné, jednoduché a uživatele neobtěžující. Jak já říkám, budiž i takto si lze pomoci. To máš to samy jako s obrázky, nikdo taky neříká, že se je nenaučí běžně luštit, teď mě napadá, že už vůbec ale nechci vidět nějaké "super" obrázky, které má problém rozluštit i uživatel. Na druhou stranu, těžko říct, co bude za pár let, uvidíme jak to pude :-).

Ján Koštial:

Keď to tak čítam, napadá ma takéto riešenie (nikde som ho ešte neodskúšal, je to prvý nápad):

Keď užívateľ vyplní formulár a stlačí tlačidlo odoslať, zobrazí sa mu rekapitulácia toho čo zadal plus nejaký obrázok, ktorý predstavuje klikaciu mapu a k tomu sa zobrazí napr. text "Kliknite na slniečko". V tom obrázku bude nejaké slniečko - server skontroluje, či užívateľ skutočne klikol na slniečko - predmety sa môžu meniť a ich poloha v obrázku samozrejme tiež. V obrázku samozrejme môže byť aj kopec mesiačikov, hviezdičiek, trpaslíkov, atď...

Pre handicapovaných užívateľov sa môže použiť nejaká zvuková podoba toho čo treba zadať.  ???

uzivatel:

Velmi neefektivne vzhladom ku komplikovanosti. Na svojom miste by som utekal zo stranok, kde po mne chcu nieco navyse.

Takze pre mna nie :)

Ján Koštial:

Nič moc navyše to nie je, kliknúť na odoslanie formulára sa aj tak musí. Zobrazovanie rekapitulácie toho, čo užívateľ zadal nie je nutné, ale ja to preferujem, lebo užívateľ má možnosť opravy.

Čo sa týka zložitosti - programuje sa to len raz...

zirafka:

Nepecujete nahodou o nejake zviratko na Neopets? Videla jsem, ze tam maji pro deti takovy pekny klikaci antispam. (-;

insekticid:

Na jednom download serveru jsem se setkal s flash animaci kde litalo 5 hvezdicek a pro download si musel kliknout na tu ktera litala nejrychleji.

Bobo:

Aneb proč to dělat jednoduše když to jde složitě...

Hooonza:

No ale klikat na obrázek by nemuselo být marné. <input type=image> odesílá souřadnice kurzoru při kliknutí. Spambot spíš zatím nebude umět kliknout přesně na nějaké místo, aby poslal dobré souřadnice, které se dají otestovat jednoduše.

Aim:

Zkuste AtlasControlToolkit.NoBot z http://atlas.asp.net/atlastoolkit/. Propracovane, funkcni, pro uzivatele maximalne jednoduche.

Danni:

No, já teda nevim, ale pokud to správně chápu, tak cíl je udělat script, kterej pro obyčejnýho uživatele bude neviditelnej, a pro spambota nepřekonatelnej... Hm. Chce to nějak ověřit, že u toho sedí člověk, ne bot. Čili co třeba změnit hodnotu nějakýho skrytýho políčka při stisknutí Submitovacího políčka nebo při zmáčknutí Enteru v okně pro příspěvek? Nebo třeba nějak bota zblbnout jinak pojmenovanýma políčkama formuláře (to uživatel nevidí) a na serveru ověřovat nějakým způsobem jestli je JMÉNO vyplněný v políčku pro TEXT a naopak, v opačným případě se jedná o BOTa... Stačí jednoduchý políčko strčený třeba za okraj stránky, tam uživatele neštve, a pojmenovat ho třeba "name", a pokud ho BOT vyplní, tak má pech... Dost pochybuju, že by si v dohledný době BOTi uměli poradit s absolutně umístěným prvkem v otázce "je vidět nebo ne?"...
Otestuju něco na ten způsob a dám vědět.

Danni:

Oprava: To první je blbost... Je to vlastně stejnej princip jako to, co tu psal někdo předtím, a pokud BOT bude mít pořádnej parser, tak je to nanic. Ale s těma CSSkama... Co třeba dát tam to políčko tak, že nebude nijak skrytý přímo, ale třeba překrytý jiným prvkem s vyšším Z-indexem, nebo tak, a pro uživatele bez CSS k němu napsat nějakou popisku jako "NEVYPLŇUJ!!!"... ještě mě napadlo CSS width&height 0px a totéž margin, padding a border. To by na nějakej (řek bych, že docela dlouhej) čas mělo stačit. Enjoy.

mis:

osobne sa mi celkom osvedcilo davat pred samotny submit este co najviac inych input prvkov (smajliky, chcekboxy a pod.), ktore uzivatel moze ale nemusi vyplnovat (oznacovat). doteraz sa ani na jedno forum ziadny robot nedostal. neviem, ci mam len stastie a roboty na mna kaslu...
zaujimalo by ma, ci vobec roboty zaujima pritomnost submit tlacitka.

jarda:

poradite nekdo jak ochranit formular,ktery zadane data odesila na mail?Posledni dobou se pres nej zacali posilat maily (spamy) na ruzne adresy.diky moc za rady! uz nevim jakou choranu udelat aby to prestalo :(

ikona Jakub Vrána OpenID:

Přečtěte si http://php.vrana.cz/e-mailovy-formular.php.

had:

mňo...takže zkusil jsem to a asi bude někde chyba...tohle řešení mi láká roboty víc, než když jsem tam měl jenom pole k opsání hodnot. asi se obě metody zkloubím dohromady, vždyť jsem měl za 10 hodin 3 spamy ! předtím to bylo kolem 1 spamu za měsíc..

Petr Novák:

Ahoj, chtěl bych se zeptat z hlediska přístupnosti protože všichni velcí jako google a seznam apod. používají CAPTCHU jak ji přečtou hlasové čtečky nevidomých když roboti ne.
Děkuji

ikona Jakub Vrána OpenID:

Viz http://pristupnost.nawebu.cz/weblog/archiv.php?search=CAPTCHA

Jens:

That is really a great idea!!

Cmelak:

Co použít refferer? Když v reffereru je moje stránka, tak asi to není robot.

ikona Jakub Vrána OpenID:

Ten se dá triviálně falšovat.

pithart:

nemohl by nekdo uvest priklad jak overit tu hodnotu formulářového pole robot? diky

robot No 5 :

Tak nevim. Asi jsem člověk...

Mirek:

Mam na svych strankach forum miniBB a resim problem spamu.
Nejsem expert, tak se ptam Vas jako odborniku. Jak tedy dostanu Ochranu formulářů proti spamu do tohoto fora? A jde to vubec?

Petr Konůpek:

Ahoj Jakube. Mám jednoduchý a dotěrný dotaz - už ti tohle řešení někdy selhalo? Mě se to jeví jako docela chytrá věc... Ale jde o to aby robot nebyl chytřejší...

ikona Jakub Vrána OpenID:

Funguje to zatím spolehlivě.

Petr Konůpek:

Tak bohu-žel zklamu... Nějakou dobu to fungovalo perfektně a teď se mi zase guestbook plní spamem :(

radek:

doufam ze hlavne tenhle webik bude fungovat dlouho.. vždy zde najdu radu.. třeba dnes když mi tohle tak trochu zachranilo krk :)))

ale ten posledni prispevek me trochu vydesil... tak nevim co mam cekat

ikona david@grudl.com:

Zaslechl jsem, že prý od 1. ledna by měl být přístup na web zpoplatněn. Ale celkem rozumnou částkou, v řádu stokorun měsíčně. Moc se o tom neví, aby si lidé nezačali web hromadně stahovat.

Daniel 'X-Ray' Dušek:

Článek je to vcelku pěkný, ale nedávno se tato ochrana na mem webu stala neucinnou, zda se, ze robot umel javascript.

had:

někde jsem četl, že je vhodné dát tam:

<input type="submit" name="polerobota" value="Neklikat" style="display: none;" />

a pak normálně v php kontrolovat, jestli nebylo tohle pole odesláno jako true - když ano, tak je jasné, že to byl spam...řeším to takhle na všech svých diskuzích a velmi dobře se mi to osvědčilo...

Petan:

muzete mi prosim poradit jak mam provest kontrolu v PHP? nejak jsem to asi nepochopil. diky.

Petan:

tak se obavam ze to reseni s display:none asi fungovat nebude nasel jsem  zde http://www.w3.org/TR/html401/interact/forms.html#h-17.13 toto: Hidden controls and controls that are not rendered because of style sheet settings may still be successful. For example:

<FORM action="..." method="post">
<P>
<INPUT type="password" style="display:none"
          name="invisible-password"
          value="mypassword">
</FORM>

will still cause a value to be paired with the name "invisible-password" and submitted with the form.

ikona Jakub Vrána OpenID:

Hodnota tlačítka se přenese jen když na něj uživatel klikne. Když je schované, tak na něj klikne jen robot.

Takže tvoje připomínka naopak způsobuje, že řešení funguje.

Pavel:

Pěkné řešení. Snad je opravdu funkční.

had:

ještě jsem se dočetl o jednom článku Michala Škrabálka, popisující opravdu dobré ochrany proti spamu - viz. http://www.dreamface.net/michal/?face=zajimavost&c=31 - v kombinaci s mým výše popsaným řešením odradilo zatím všechny roboty.

Vložit příspěvek

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2014 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.