AntispamControl – jednoduchý antispam

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
nanuqcz
Člen | 822
+
0
-

Ahoj,
implementoval jsem návrh pasivního antispamu od Jakuba Vrány pro Nette formuláře.

Použití

$form->addAntispam();  // to je vše :-)

Instalace

  • Stáhněte soubor AntispamControl.php a uložte do adresáře libs
  • V BasePresenteru registrujte AntispamControl jako rozšíření formulářů
class BasePresenter
{
    function startup()
    {
        AntispamControl::register();
    }
}

Stránka s Addonem

Addon má svoji stránku zde.

Zatím jsem to nasadil na jeden web, kde chodil spam, a od té doby dobrý – asi měsíc bez jediného spamu. Pokud to ale nebude stačit a byl by zájem, přidám i další typy pasivních ochran (kontrola doby vyplňování formuláře apod.)

Editoval nanuqcz (18. 4. 2012 10:29)

Ot@s
Backer | 476
+
0
-

Dlouho jsem se šponoval, že něco takového, hlavně jednoduchého, urobím. Díky! Určitě s tím do Addon, co?

Filip Procházka
Moderator | 4668
+
0
-
$this->addRule(~Form::FILLED);
nanuqcz
Člen | 822
+
0
-

HosipLan: Díky, upravil jsem.

Rozšíření přidáno do Addonů.

Tomáš Votruba
Moderator | 1114
+
0
-

Mám bug při manuálním renderu:

{input antispam}

Pro fčnost musím upravit ř. 79

// z
document.getElementById('" . $control[0]->id . "').parentNode.parentNode.style.display = 'none';
// na
document.getElementById('" . $control[0]->id . "').style.display = 'none';

aby se mi neschovával celý formulář.

jtousek
Člen | 951
+
0
-

Chybná anotace u metody getControl. Jinak dobrá práce. ;-)

nanuqcz
Člen | 822
+
0
-

Schmutzka: Tohle mě napadlo už při vytváření AntispamControlu, jenom jsem tehdy nevěděl, jak to vyřešit. Zkus aktuální verzi (právě jsem ji přizpůsobil i pro manuální render), u mě funguje ;-)

jtousek: Jj máš pravdu, opraveno :-) Díky

uestla
Backer | 796
+
0
-

Osobně se mi tahle „přehnaná“ lenost moc nelíbí/nehodí. Jako pomocníka bych to vnímal, přidalo-li by mi to antispamový prvek a nastavilo hodnotu, kterou to má/nemá mít.

Kdybych si formulář vykreslil hodně po svém, už mi bude generovaný javascript dělat neplechu. Mohl bych si ho ručně upravit, ale pak už není komponenta použitelná plošně, ale jen pro daný případ.

Vytvářet děděné komponenty pro každý zvláštní případ také není moudré.

Osobně si skrývání prvků při zapnutém javascriptu realizuji pomocí triku z legendárního komentáře u Jakuba Vrány:

<style>.js .hidden { display: none; }</style>

<body>
	<script type="text/javascript">document.body.className += ' js';</script>
{form ...}
	{input antispam, class => 'hidden'}
{/form}

Myšlenka je každopádně dobrá, můj výstup je zde.

Editoval uestla (6. 5. 2012 16:11)

nanuqcz
Člen | 822
+
0
-

uestla: Taky hezké. Jen jsem nenašel, kde se v tvojem výstupu nastavuje class="hidden" pro formulář renderovaný klasicky (přes DefaultFormRenderer).

Každopádně přehnaná lenost mě osobně vyhoduje. V tvojem řešení musím kromě „instalace“ AntispamControlu ještě přidat jeden řádek do CSS a jeden řádek javascriptů :-) Ale tohle je věc názoru (jednoduchost vs. komplexnost)

uestla
Backer | 796
+
0
-

Tak samozřejmě, každý svého štěstí strůjcem. Původně jsem tam přidání třídy napevno měl, ale vykresluji-li ručně do tabulky, bylo by zbytečné mít ve výsledku něco jako

<tr class="hidden"> <!-- přidané mnou -->
	<td><input ... class="hidden"></td> <!-- způsobené na straně serveru -->
</tr>

Proto nevidím problém – chci-li vykreslit DefaultRendererem a vím o tom – ve využití vrácené hodnoty:

$antispam = $form->addAntispam();
$antispam->controlPrototype->class('hidden');
$antispam->labelPrototype->class('hidden');

Osobně ale daleko častěji vykresluji pomocí {form ...} maker.

O generovaném javascriptu asi ani nemluvě :-( Ale proti gustu žádný dišputát (abychom nezůstali pouze u jednoho moudrosloví ;-)).

Editoval uestla (6. 5. 2012 20:34)

Tomáš Votruba
Moderator | 1114
+
0
-

Tak jsem nasadil do twitter-modal (možná to má nějakou relevanci) a chodí mi mnohem více spamů. Mohl bych poprosit ještě o nějaké zmiňované ochrany? Případně doporučení, díky

nanuqcz
Člen | 822
+
0
-

Schumtzka: Ještě více spamů než předtím? :-) To je zvláštní. Za 3 týdny končím školu a státnicuju, tak nevím, jestli se k tomu teď dostanu. Pokud by se ti ale chtělo, můžeš tam zkusit implementovat třetí bod z tohohle článku, pokud se k tomu nedostanu dřív.

nanuqcz
Člen | 822
+
0
-

Tak nakonec jsem dostal chuť to tam přidat sám, vyzkoušej :-)

Tomáš Votruba
Moderator | 1114
+
0
-

Same here :) díky, nasazeno.

MartinitCZ
Člen | 580
+
0
-

Mnohem jednodušší řešení mi přijde přidat input „email“, který bude skryt pro uživatele, ale bot ho vyplní.

A po odeslání jen kontrolovat, jestli je prázdný ⇒ pokračovat, něco obsahuje ⇒ redirect doPryč.

Ale nikdy jsem nezkoumal úspešnost určitých řešení proti spamu ;)

nanuqcz
Člen | 822
+
0
-

martinit: Ale vždyť přesně takhle ten addon funguje :-)

Akorát se pole nejmenuje email. Ale pokud chceš, aby se tak jmenovalo, jde to jednoduše nastavit:

$form->addAntispam('email');

EDIT: Možná tě zmátlo, že se kontroluje doba odeslání příspěvku. To je jen kontrola „navíc“ ke způsobu, který jsi popsal ty ;-)

Editoval nanuqcz (10. 5. 2012 15:14)

ic
Člen | 430
+
0
-

Nevadí tohle nástrojům na automatické vyplňování formulářů ( http://www.zive.cz/…default.aspx )? Myslím, že takový nástroj by antispamem neprošel.

Tomáš Votruba
Moderator | 1114
+
0
-

@ic: Nerozumím, co tím tohle myslíš. Pokud náhodou reaguješ na čas, tak na login form se antispam nehodí (kde se hodí automatické vyplňování), ale všude jinde uživatel aspoň něco napsat musí (heslo, adresu…).

Také by se hodilo vědět, jak dlouho to trvá robotům :).

@nanuqcz: Díky, čas funguje!

nanuqcz
Člen | 822
+
0
-

Také by se hodilo vědět, jak dlouho to trvá robotům :).

Až bude čas, přemýšlel jsem, že si udělám nějaké statistiky :-) Ale jestli tě to moc zajímá, tak si přidej do addRule nějaké logovací funkce.

$form->addHidden('form_created', time())
	->addRule(
		function($item){
			$value = (int)$item->value;

			//------log
			if ($value <= (time() - AntispamControl::$minDelay)) {
				file_put_contents('antispam.log', 'Fill time: ' + (time() - AntispamControl::$minDelay) + ' s \n', FILE_APPEND);
			}
			//------/

			return $value <= (time() - AntispamControl::$minDelay);
		},
		$msg
	);

Editoval nanuqcz (10. 5. 2012 19:40)

Tomáš Votruba
Moderator | 1114
+
0
-

Rád přispěji svými daty :) Aplikováno, díky!

Bazylek
Člen | 22
+
0
-

Ahojte,
prosím o radu, při implementaci došlo k chybě :

Argument 1 passed to Nette\Forms\AntispamControl::addAntispamScript() must be an instance of Nette\Utils\Html, instance of Nette\Web\Html given, called in C:\website\inlinesports\libs\AntispamControl.php on line 82 and defined

nemůžu přijít na to, kde dělám chybu.

HomepagePresenter

public function createComponentKontaktForm()
{
        $form = new AppForm($this, 'kontaktForm');
        $model = new \UsersModel();
        $uzivemail = $this->getParam('id');
        $defaults = $model->getUser($uzivemail);
        $userExists = $defaults && !empty($defaults);
        $form->addText('jmeno', 'Vaše jméno', 35)
             ->addRule($form::FILLED, 'Vypňte Vaše jméno');
        $form->addText('email', 'Váš e-mail', 35)
             ->addRule($form::FILLED, 'Vyplňte svůj email')
             ->addRule($form::EMAIL, 'Vyplňte platný email');
        $form->addTextArea('zprava', 'Text emailové zprávy', 40, 200);
        $form->addSubmit('save', 'Odeslat')
             ->onClick[] = callback($this, 'emailOdesli');
        $form->renderer->wrappers['controls']['container'] = 'dl';
        $form->renderer->wrappers['pair']['container'] = NULL;
        $form->renderer->wrappers['label']['container'] = 'dt';
        $form->renderer->wrappers['control']['container'] = 'dt';
        $form->addAntispam();
        return $form;
}

Děkuji za každou radu

Ot@s
Backer | 476
+
0
-

Vypadá to, že používáš starší vezi Nette (asi 2beta). Pokud nemůžeš provést update Nette, tak by teoreticky v AntispamControl.php u use stačilo přepsat Nette\Utils\Html na Nette\Web\Html.

Bazylek
Člen | 22
+
0
-

To jsem zkoušel,
use Nette\Forms\Controls\TextInput,
Nette\Forms\Form,
Nette\Utils\Html,
Nette\Web\Html;
ale hazeí mi to
Cannot use Nette\Web\Html as Html because the name is already in use
Pokud bych přešel na novou verzi, tak bych musel předělat celý web. Bylo by to moc pracné.

Děkuji za radu, špatně jsem přečtl tvou odpověď.
s tímto to funguje
use Nette\Forms\Controls\TextInput,
Nette\Forms\Form,
Nette\Web\Html;

Editoval Bazylek (4. 6. 2012 13:46)

Jesper
Člen | 4
+
0
-

Zdravím, nevím jestli něco dělám zle či ne, ale nette mne vždy zdupe. Verze 2.0.10

Nette\InvalidStateException

Method BasePresenter::startup() or its descendant doesn't call parent::startup().

Jsem začátečník s Nette a postupoval jsem přesně podle návodu. Díky za rady .. třeba je fakt chyba jen na mé straně.

Foowie
Člen | 269
+
0
-

Podívej se do presenterů (BasePresenter, …), jestli v jejich metodách startup se volá parent::startup();

jolan
Člen | 5
+
0
-

Navrhuji doplnit jěště podmínku

$this->addRule(Form::EQUAL, $msg, '');

Pokud to totiž chápu správně, tak ~Form::FILLED projde i v případě, kdy položka nebyla v POST-u vůbec zaslána. To se ale často stáva, protože roboti (z mých zkušeností) stahují HTML kód formuláře pouze jednou a následně na něj už sypou POST-ové požadavky podle položek, které Form měl při první návštěve. Když tam ale správce webu doplní antispamovou ochranu až poté, co zjistí, že mu chodí moc spamu, robot toto pole už v POST-ových požadavcích nedoplní, tudíž je podmínka pokaždé true.

Filip Procházka napsal(a):

$this->addRule(~Form::FILLED);

Editoval jolan (6. 1. 2014 16:55)

jolan
Člen | 5
+
0
-

jolan napsal(a):

protože roboti (z mých zkušeností) stahují HTML kód formuláře pouze jednou a následně na něj už sypou POST-ové požadavky podle položek, které Form měl při první návštěve

Z toho samého důvodu bohužel moc nefunguje ani ochrana časovým razítkem…

amik
Člen | 118
+
0
-

Žije tenhle addon ještě někde? odkaz v prvním příspěvku píše page not found

MartinitCZ
Člen | 580
+
+1
-

Addon je zbytečnost. Stačí přidat do továrničky formuláře:

$this->addHidden('email');

nebo

$this->addHidden('mail')

Roboti toto rádi vyplní, jelikož je to „email“ pole :)

Ve zpracování formuláře použiješ:

if ($values->email) { // Pokud je toto vyplněno, tak to nejspíš bude robot (případně nějaký štoura :D)

	$this->redirect('Homepage:default');

}
mrtnzlml
Člen | 140
+
-2
-

amik napsal(a):

Žije tenhle addon ještě někde? odkaz v prvním příspěvku píše page not found

Třeba zde