Blokování návštěvníka pomocí IP adresy

Webster.K
Člen | 211
+
0
-

Zdravím všechny, existuje v nette nějaký způsob, jak když se uživatel špatně třeba 3× přihlásí, tak že je pro web jeho IP pak blokovaná, aby se vůbec nenačetl?

Podařilo se mi z $this->getHttpRequest() při přihlášení dostat IP adresu, odkud se návštěvník přihlašuje/snaží přihlásit. Co ale s tou IP dál? Editovat v kodu .htaccess soubor mi nepřijde úplně ok, abych do něj přidával pořád řádky „deny from xxx.xxx.xxx.xxx“. Hlavně věřím tomu, že za chvíli by ten soubor byl nesmyslně velikej a tak by to mohlo dost zpomalit načítání. Existuje v nette tedy nějaký elegantní řešení, jak tomuhle předejít?

Kamil Valenta
Člen | 815
+
0
-

Klíčové je, co si představuješ pod „aby se vůbec nenačetl“?
Protože odpověď je: ne, v nette nemá šanci nic takového být. Aby request zařízlo nette, musí se načíst alespoň „něco“.
Pokud bys to chtěl držet takto čistě, že se skutečně nenačte nic, můžeš použít třeba Fail2ban nad vlastním logem, který si budeš v nette generovat.

Jen pozor, pokud server používá IPv6, nejsem si jist, že už mají ve Fail2ban podporu, spíš myslím, že ne.

Editoval Kamil Valenta (17. 7. 9:07)

Webster.K
Člen | 211
+
0
-

Mě jde o to, udělat cokoliv, co funguje stejně jako zmíněný .htaccess, když do něj dám třeba „deny from moje_ip“, rovnou ten web ani nic nenačte. Jde mi práve o to, že jako první je na webu přihlášení. Bez přihlášení se tam vůbec nedá dostat. Smysl je tedy ten, že když někdo z nějaké IP zkouší loginy, po chvíli se práve upraví .htaccess na jeho IP a v tu chvíli se vůbec nic nenačte, apache ho rovnou odpojuje :) a mě právě zajímá, zda neexistuje nějaká lepší verze tohodle přímo v nette. Klidně to může dělat to samé. Nebo teoreticky klidně když se vytváří nějaká nette část to vezme proti DB data a zjistí, jo, tahle IP existuje, tak prostě to vrátí prázdnou stránku s „ničím“. nebo klidne zprávou že IP je blokována, to už je celkem jedno. Předpokládám, že někde v BasePresenteru ve funkci startup() proti DB ověřím IP a pokud tam existuje, tak jen zobrazim něco? Nebo je to špatný postup?

Editoval Webster.K (17. 7. 17:39)

Webster.K
Člen | 211
+
0
-

Tak mám řešení pomocí nette, jen nevím, zda je tohle řešení přijatelné, nicméně je funkční, nebo se tak jeví:

protected function startup() {
        parent::startup();

        //overeni proti DB zda IP muze neco zobrazit
        $ziskaniIP = $this->getHttpRequest();
        //Debugger::barDump($ziskaniIP->remoteAddress);
        $blokovanaIP = $this->database->table('zablokovany_ip')->select('pocet')->where('ip',$ziskaniIP->remoteAddress)->fetch();
        //Debugger::barDump($blokovanaIP->pocet);

        if($blokovanaIP == null){
            //pohoda - neni zadny zaznam
            //Debugger::barDump('null - není potřeba blokovat');
        }elseif($blokovanaIP->pocet>=3){
            //tohle zablokovat
            //Debugger::barDump('ted ma byt zablokovano');
            exit;
        }
}
Šaman
Člen | 2658
+
0
-

Jop, v BasePresenteru metoda startup() je typické místo, kde se kontroluje základní oprávnění. Tedy jestli vůbec pustit uživatele dál. Normálně tam přesměruješ na přihlašovací stránku, nebo někam, kde mu napíšeš že má banán.

Koukám, že v posledních ukázkách to David řeší pomocí traity, ale princip je stejný jako dědění od BasePresenteru.

Editoval Šaman (17. 7. 17:58)

m.brecher
Generous Backer | 863
+
-1
-

@Šaman

Jop, v BasePresenteru metoda startup() je typické místo, kde se kontroluje základní oprávnění.

Ano, startup() je ideální, ale ip ban není typické oprávnění a protože ověření ip banu zabere nějakou režii, je ideálním místem SignPresenter::startup() a bezpochyby stačí ověřit ban jen při pokusu o přihlášení.

m.brecher
Generous Backer | 863
+
-1
-

@WebsterK

$blokovanaIP->pocet>=3

Při pohledu na banovací pravidlo pocet>=3 jsem si vzpomněl jak kdysi dávno nejmenovaný webhosting měl pravidlo při přihlášení na ftp pocet>=3 a protože jsem zvyklý dát cca 3 pokusy když něco nehraje, tak jsem se při zřizování hostingu vždy spolehlivě zabanoval a musel volat dispečink pro odbanování.

Infanticide0
Člen | 103
+
0
-

Můžeš si načíst zablokovaný IP z databáze už v index.php, ještě než se spustí Nette App, když neprojde, jenom místo spuštění Aplikace vrátíš třeba 403 a ukončíš skript. Zároveň můžeš cachovat seznam IP banů a režii čtení db dat minimalizovat.

A nemusíš tim špinit presentery a kontrolovat to pak třeba znovu v API modulu apod.

Editoval Infanticide0 (17. 7. 19:55)

Webster.K
Člen | 211
+
0
-

Infanticide0 napsal(a):

Můžeš si načíst zablokovaný IP z databáze už v index.php, ještě než se spustí Nette App, když neprojde, jenom místo spuštění Aplikace vrátíš třeba 403 a ukončíš skript. Zároveň můžeš cachovat seznam IP banů a režii čtení db dat minimalizovat.

A nemusíš tim špinit presentery a kontrolovat to pak třeba znovu v API modulu apod.

Nejradši bych to vyřešil už na straně Apache aby odněkud našel seznam IP a když se schoduje, tak blokuje a na PHP se vůbec nedostalo :D ale nějak mi nedochází, jak to vůbec udělat, proto jsem tak nějak „trapně“ nechal nette, aby editovalo .htaccess soubor. Což neni ideální, když se něco nepovede, tak chyba v něm končí http500 :D a při více záznamech je to pak fakt pomalý (jen tak na stroji doma jsem v něm měl 1000 řádků co byli testovací) Jinak v SignPresenteru při přihlášení se IP pochopitelně kontroluje, je tam:

public function signInFormSucceeded(Form $form, \stdClass $data): void {
        try {
            //prihlaseni a veci okolo nej
        } catch (Nette\Security\AuthenticationException $e) {
            $data = $this->getHttpRequest();
            //Debugger::barDump($data->remoteAddress);
            $blokIP = $this->database->table('zablokovany_ip')->select('pocet')->where('ip',$data->remoteAddress)->fetch();
            if($blokIP == null){
                //pridat
                $this->database->table('zablokovany_ip')->insert(['ip'=>$data->remoteAddress,'pocet'=>1]);
            }else{
                //existuje - upravit
                $this->database->query('UPDATE zablokovany_ip SET pocet = pocet + 1 WHERE ip = ?', $data->remoteAddress);
            }
            //Nesprávné přihlašovací jméno nebo heslo.
            $form->addError('spatne jmeno/heslo');
        }
    }
Martin Dřímal
Člen | 20
+
+3
-

Webster.K napsal(a):
Nejradši bych to vyřešil už na straně Apache…

Takže nějaký VPS, který máš pod kontrolou? Kdysi jsem na to používal fail2ban, který koukal do apache logu a ip adresy pokoušející se přihlásit často zablokoval (dočasně a po nastaveném čase je zase pustí).
Něco jako:

jail.local

[apache-login]
enabled  = true
port     = http,https
filter   = apache-login
logpath  = /var/www/nejakyweb.com/log/access.log
maxretry = 3
findtime = 300
bantime  = 600

/etc/fail2ban/filter.d/apache-login.conf

[Definition]
failregex = ^<HOST> - - \[.*\] "POST /tady-se-prihlasuje HTTP/.*" 200
ignoreregex =