Ošetření neexistujících route – triviální úroky

milanb
Člen | 64
+
0
-

Dobrý den,
často posledí dobou zaznamenávám triviální pokusy útočníků dostat se do naší aplikace v domění, že jde o WordPress. Často to vypadá jako např. volání následujícího URL: https://naseaplikace.cz/wp-login.php
To pak vede na výjimku se záznamem v logu, který obsahuje toto:
Nette\MemberAccessException: Cannot read an undeclared property Nette\Security\User::$user_role_id. in /home/m/naseaplikace/www/is/vendor/nette/utils/src/Utils/ObjectMixin.php:173
Jak ošetřit takovou věc, aby aplikace (server) vrátila HTTP kód 404 Not found a nezaznamenala tuhle výjimku?
Děkuji za radu.

nightfish
Člen | 474
+
+2
-

@milanb
Stačí opravit chybu, kterou popisuje chybová hláška. Tzn. najít místo, kde se pracuje s $user_role_id (mělo by být patrné ze stacktrace uvedené výjimky) a opravit jej, aby se aplikace při přístupu na neexistující stránku nepokoušela s touto proměnnou pracovat. Tipnul bych si, že tuto proměnnou budete mít v layoutu a nastavovat v nějakém BasePresenteru, avšak ErrorPresenter ji nenastavuje…

Michalek
Člen | 210
+
+5
-

Mám to (společně s x dalšíma věcma) rovnou v htaccess na rewrite a aplikaci s tím vůbec nezatěžuju…

RewriteRule ^wp-login.php - [R=404,L]
kminekmatej
Generous Backer | 34
+
0
-

Zapni si debug mód a otevři si tu url v prohlížeči. Měla by ti vypadnout tracy s logem, tam to krásně dohledáš

dakur
Člen | 493
+
+4
-

kminekmatej napsal(a):

Zapni si debug mód

To není na produkčním serveru moc dobrý nápad – všem se objeví tracy bar, který vypíše komplet všechny informace o použitých packages, sestaveném DI či přihlašovací údaje k db či jiným službám.

Tracy s logem najdeš i ve složce s projektem v podadresáři log/ jako HTML soubor, tu si můžeš stáhnout a otevřít lokálně, jestli potřebuješ.

Editoval dakur (20. 12. 2023 9:27)

kminekmatej
Generous Backer | 34
+
+2
-

@dakur Automaticky předpokládám že si debug mód zapne jen pro svou IP, nikoliv globálně (jinak máš samozřejmě pravdu).
V log filu se nezobrazuje tracy bar, který je při debugu poměrně handy (alespoň pro mě – tady by mohl stačit jen logfile)

milanb
Člen | 64
+
0
-

Michalek napsal(a):

Mám to (společně s x dalšíma věcma) rovnou v htaccess na rewrite a aplikaci s tím vůbec nezatěžuju…

RewriteRule ^wp-login.php - [R=404,L]

Díky, ale takhle to nepůjde, ti útočníci zkouší různé varianty, nejen právě tento soubor.

milanb
Člen | 64
+
0
-

kminekmatej napsal(a):

@dakur Automaticky předpokládám že si debug mód zapne jen pro svou IP, nikoliv globálně (jinak máš samozřejmě pravdu).
V log filu se nezobrazuje tracy bar, který je při debugu poměrně handy (alespoň pro mě – tady by mohl stačit jen logfile)

Díky @dakur i @kminekmatej, samozřejmě jsem nezapnul pro všechny na produkci Tracy a mám to jen pro vybranou IP adresu, to už se mi podařilo snad úspěšně.

A to právě vedlo k výjimce:

Nette\Application\BadRequestException #404
Cannot load presenter 'WpLogin:Php', class 'App\WpLoginModule\Presenters\PhpPresenter' was not found.
...
Nette\Application\InvalidPresenterException
Cannot load presenter 'WpLogin:Php', class 'App\WpLoginModule\Presenters\PhpPresenter' was not found.

O co mi jde, je njít místo, kde mám tuto a jí podobné typy výjimek odchytit, ošetřit vlastním kódem a hlavně nezapisovat pak už do logu jako exception a nedostat taky v každém takovém případě emailovou notifikaci.

Pavel Kravčík
Člen | 1182
+
+1
-

Do ErrorPresenteru můžeš doplnit něco podobného (pseudokód):

pf run(): Response
{
	$e = $request->getParameter('exception');

	if($e instanceof \Nette\Application\BadRequestException || $e->getCode() === 404)
	{
		//log to file.txt
	}
}
m.brecher
Generous Backer | 762
+
0
-

@milanb

O co mi jde, je najít místo, kde mám tuto a jí podobné typy výjimek odchytit, ošetřit vlastním kódem a hlavně nezapisovat pak už do logu jako exception a nedostat taky v každém takovém případě emailovou notifikaci.

systémové řešení naznačil @nightfish ve svém commentu https://forum.nette.org/…vialni-uroky#… chybová stránka při vykreslení volá nějaké šablony a layouty, kde je zřejmě vyžadováno $user_role_id a aktuální error presenter toto nedodá. Nette pak vyhodí tu výjimku. Na 90% to bude tím.

Jak to vyřešit?

Správně a přehledně ošetřit 404 × 500 chyby není vůbec triviální. V principu je potřeba od sebe oddělit chyby 404 a 500 a každou skupinu ošetřit úplně jiným způsobem. 500 je průšvih, který se musí logovat a ideálně notifikovat emailem. Naopak 404 vznikají díky robotům dnes a denně a logovat/notifikovat obvykle dost obtěžuje, obvykle se požaduje vykreslení nějakého standardního layoutu včetně navigace, aby se uživatel zbytečně neplašil. Všichni asi používáme koncept z nette web-projekt skeletonu, kde ErrorPresenter přehodí 404 na Error4xxPresenter a 500 zaloguje + vykreslí přímo šablonu 500.latte

Pokud se 404 vykresluje do standardního layoutu webu, může snadno dojít k chybám toho typu, že chybí nějaké proměnné pro layout. Layout je potřeba pro účely 404 modifikovat. Já to řeším tak, že mám v aplikaci v hierarchii dva layouty, první definuje umístění bloků v základní kostře webu, podřízený layout definuje ty bloky. Můžu tak mít @baseLayout.latte a podřízené @frontLayout.latte a @adminLayout.latte. Pro chybovou 404 stránku si udělám speciální @404Layout.latte a 404 vykreslím do kaskády layoutů takto:
@baseLayout.latte@frontLayout.latte@404Layout.latte. @404Layout.latte nedělá nic, pouze maže problematické bloky v nadřazeném layoutu @frontLayout.latte. Třeba nějaký blok, kde se používá to problematické $user_role_id. Samozřejmě je potřeba mít layout kvalitně a přehledně rozčleněný do logických bloků.

milanb
Člen | 64
+
0
-

OK, dík ymoc @m.brecher, to dává smysl, vrhnu se tímto směrem. Je to starý kód, ne můj, který možná vyšel z nette web-projekt skeletonu, ale pak se začalo bastlit a lepit… Všichni to asi známe :-)

Michalek
Člen | 210
+
0
-

Navzdory řečenému mi pořád přijde nejlepší pořešit to přes .htaccess, než zatěžovat aplikaci.
Přece nikdo neříká, že to nemůže vypadat takhle jako u mě (je to pořád jen část) :-)
Těch nejčastějších zkoušených stránek zas není tolik, aby to nešlo vychytat.

Samozřejmě jsem to nevymýšlel sám, těch připravených řešení, z kterých se dá vybrat potřebné, asi pár je:

<IfModule mod_alias.c>
  RedirectMatch 403 (?i)([a-z0-9]{2000})
  RedirectMatch 403 (?i)(https?|ftp|php):/
  RedirectMatch 403 (?i)(base64_encode)(.*)(\()
  RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\.
  RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&amp;?)/?$
  RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")
  RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\s|\{|\}|\[|\]|\|)
  RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|etc/passwd|muieblack)
  RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)
  RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$
  RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php
</IfModule>

Editoval Michalek (2. 1. 19:10)

m.brecher
Generous Backer | 762
+
+4
-

@Michalek

Navzdory řečenému mi pořád přijde nejlepší pořešit to přes .htaccess, než zatěžovat aplikaci.

.htacces může zachytit hodně opakujících se útoků, ale stejně je potřeba mít v pozadí stabilní a spolehlivý error presenter + příslušné 404/500 šablony.