Route::SECURED a defaultFlags v HTTPS pod Nette 2.4

David Grudl
Nette Core | 8118
+
+8
-

Přístup Nette k HTTPS si zasluhoval zrevidovat. Jednak se objevují issue, že by to chtělo nové flagy:

a také dochází k nedorozuměním, jaký smysl vlastně flag IRouter::SECURED má:

https://forum.nette.org/…je-https-100

Ve stručnosti: flag SECURED vznikl kdysi pradávno a proto, aby na HTTPS bylo možné Nette vůbec provozovat, tedy aby fungovala kanonizace. Což je unikátní vlastnost Nette, kdy se Presentery přesměrovávají na kanonickou URL, kterou vygeneruje router. A flag router instruuje k tomu, aby generoval odkazy s protokolem https. Nic víc, nic míň. Tedy aby nedocházelo k přesměrovávání z HTTPS na HTTP. Přičemž je mu jedno, ze kterého protokolu přicházíte, na to nehledí, ať už je flag aktivní nebo ne.

V žádném případě nefunguje jako zabezpečení proti vstupu přes HTTP. Na HTTPS se přesměrovává jen díky kanonizaci, což je věc spjatá se SEO, nikoliv bezpečností. Ke kanonizaci nemusí dojít, například při odeslání formuláře nebo ajaxovém požadavku. Přesměrování celého provozu by totiž měla zajistit konfigurace serveru, třeba v .htaccess.

Pokud celý web nebo subdoménu přesouvám na HTTPS, musím ve 2.3 všem routám nastavit flag SECURED, což se dá zjednodušit tím, že nastavím proměnnou Route::$defaultFlags (statické proměnné nejsou pěkné, je to jedna z posledních v Nette).


V nette 2.4 se routy chovají malinko jinak:

Při generování URL použijí stejný protokol, jaký aktuálně používáte

Pro weby, které běží kompletně na HTTPS, tak odpadá nutnost flag uvádět a v důsledku toho mizí potřeba mít statickou proměnnou $defaultFlags.

Pro weby, které mají více subdomén a některé jsou na HTTPS a jiné nikoliv (což není z bezpečnostního hlediska ideální), je stále potřeba flag pro příslušné subdomény uvést (tj. u rout, jejichž maska začíná na //). V tomto případě ale také ztrácí smysl $defaultFlags. se místo flagu rovnou zapíše protokol v masce.

U webů, které mají pod HTTPS jen určité stránky, tj. mají flag SECURED uvedený u routy jejíž maska NEzačíná na //, dojde k vyhození noticky, že tento flag je deprecated. Toto upozornění má smysl, protože flag SECURED skutečně nezajišťuje, že uživatel přišel na stránku přes HTTPS, viz výše, a vlastně mohl vytvářet falešný pocit. Uživatel musí přesměrování zajistit konfigurací serveru, třeba přes .htaccess a flag může potom odstranit.

Proměnná $defaultFlags je tedy deprecated a flag SECURED je deprecated krom případu, že ho uvedete u routy s maskou začínající na //.

Myiyk
Člen | 321
+
0
-

Jak to bude fungovat v Nette 3 ?

Když to je teď deprecated, v Nette3 to nejspíš nebude. Přijde mi divné, aby potom šly dělat secured routy pouze na absolutní adresy.

Editoval Myiyk (20. 5. 2016 18:18)

greeny
Člen | 405
+
0
-

Myiyk napsal(a):

Jak to bude fungovat v Nette 3 ?

Když to je teď deprecated, v Nette3 to nejspíš nebude. Přijde mi divné, aby potom šly dělat secured routy pouze na absolutní adresy.

Viz poznámka „pod čarou“ ->

V poslední verzi nette/application se routy chovají malinko jinak:

Při generování URL vedoucí na stejnou doménu a subdoménu, z jaké jste přišli, použijí stejný protokol.

Pro weby, které běží kompletně na HTTPS, tak odpadá nutnost flag uvádět a v důsledku toho mizí potřeba mít statickou proměnnou $defaultFlags.

Myiyk
Člen | 321
+
0
-

Ano, to je situace když vedou na stejnou doménu a subdoménu. Ale co se stane, když ne? Bude odkaz https?
Už jsem to cca pochopil. Pokud routa bude relativní, použije se https podle aktuální adresy. A když bude absolutní, půjde použít SECURED. + Bude asi automaticky secured?

Editoval Myiyk (20. 5. 2016 21:00)

Aurielle
Člen | 1281
+
0
-

Vítám tuhle změnu, dost to zjednoduší nastavování rout na https-only webech. Díky!

Napadá mě jedna otázka: mám routy pro různé subdomény, všechny chci mít pod HTTPS. Musím uvádět nějaký flag nebo stačí konfigurací serveru zajistit, že budou přicházet pouze https požadavky a všechno bude fungovat správně?

David Grudl
Nette Core | 8118
+
+3
-

Hmm, tohle jsem nedomyslel. Teď to funguje tak, že stejný protokol se používá při odkazu na stejnou doménu + subdoménu. Což znamená, že když mám vícesubdoménový web kompletně na HTTPS, musel bych u každé routy se subdoménou v masce (což jsou vlastně všechny) uvádět i flag SECURED…

Co s tím.

Protože web běžící komplet na HTTPS je ideální stav, mělo by tomu být výchozí chování uzpůsobeno. Dalo by se to změnit tak, že se protokol bude přenášet i při odkazech na jiné subdomény v rámci domény. Rozlišit, co je doména a co subdomény je dost problém (*.co.uk), takže možná by bylo řešením to nerozlišovat vůbec.

Co když některá subdoména na HTTPS není? Na to by se musel přidat nový flag NONSECURED, ale říkám si, že srozumitelnější bude umožnit zápis Route('http://domain.cz/<presenter>)` a potažmo i Route('https://domain.cz/<presenter>), což by vlastně nahradilo flag SECURED. Zápis bez protokolu `Route('//domain.cz/<presenter>)` pak vlastně evokuje, že protokol bude přenášen, protože právě tak to chodí i v prohlížečích.

DavidKrmela
Člen | 5
+
+3
-

Pokud bude nové chování a způsob zápisu zachováno, bylo by možné přidat krom placeholderů %basePath%, %tld%, %domain% a %sld% také placeholder %host%? Aby šlo routy zapisovat stylem Route('https://%host%/%basePath%/<presenter>'), které šlo dříve zapsat pomocí Route('<presenter>', [], Route::SECURED).

David Grudl
Nette Core | 8118
+
+2
-

Klidně, pošleš pull request?

DavidKrmela
Člen | 5
+
+1
-

Ok, je tam.

Zuben45
Člen | 268
+
0
-

ze začátku jsem byl zklamán, ale poté co jsem si pohrál s htaccess už ve zrušení defaultFlags nevidím problém, ale asi by bylo dobré napsat do dokumentace nějaký ten příklad :)
Jinak palec hore :)

David Grudl
Nette Core | 8118
+
+3
-

Bude fajn, pokud něco vymyslíš a pošleš sem https://github.com/nette/docs

Zuben45
Člen | 268
+
+4
-

David Grudl napsal(a):

Bude fajn, pokud něco vymyslíš a pošleš sem https://github.com/nette/docs

Dobrá tedy, nebyl jsem si jistý jestli by byl vůbec o to zájem :), zítra něco sepíši.

EDIT: @DavidGrudl PR – https://github.com/…ocs/pull/451

Editoval Zuben45 (7. 6. 2016 15:54)

MKI-Miro
Člen | 265
+
0
-

Ahojte

ako teda spravne nastavit https ?

momentalne to mam takto a chcel by som to prerobit na https

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ /www/ [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/www/
    RewriteRule ^(.*)$ /www/$1
</IfModule>

dakujem

Lukes
Silver Partner | 68
+
+3
-

Přidej do mod_rewrite.c

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
zerb
Člen | 7
+
0
-

mam rovnaky problem ako MKI-Miro, pridal som do htaccess dve pravidla ako pise Lukes, ale web sa mi dostal do nekonecnej slucky a prehliadac skape na too many redirects. Pouzivam nette 2.4, v htaccess mam rovnaky obsah ako MKI-Miro. Dakujem za pomoc

David Matějka
Moderator | 6445
+
0
-

@zerb kde mas hosting? neni ten apache za nejakou proxy, na kterou uz jde jen http(bez s) pozadavek?

Jiří Nápravník
Člen | 710
+
0
-

dneska jsem narazil na neco podobneho na onebitu: https://www.onehelp.cz/…oci-htaccess

zerb
Člen | 7
+
0
-

@DavidMatějka hosting mam na websupport.sk, doteraz som pouzival nette 2.3 a https routy som si vynutil cez secured flag v routerfactory, vsetko fungovalo. Po upgrade nette na 2.4 sa to rozsypalo, kedze flagy v routeri su deprecated. Sucasne s tym potrebujem requesty posielat do zlozky www. V .htaccess v korenovom adresari mam toto:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ /www/ [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/www/
    RewriteRule ^(.*)$ /www/$1
</IfModule>

a tu potrebujem pridat este pravidlo aby requesty boli vzdy na https a sucasne ostalo posielanie requestov do zlozky www. Do apache konfiguracie sa nevyznam a neviem si s tym dat rady.

alNath
Člen | 17
+
0
-

Tiez som to tam riesil, zial nic neporiesil. Vid https://forum.nette.org/…tovani-https#…

MKI-Miro
Člen | 265
+
0
-

Ja som to vyriesil takto:

do websupportu som napisal aby mi zmenili root adresara do www adresara a v nom vyzera moje htaccess takto:

# Apache configuration file (see httpd.apache.org/docs/current/mod/quickreference.html)

# disable directory listing
<IfModule mod_autoindex.c>
	Options -Indexes
</IfModule>

# enable cool URL
<IfModule mod_rewrite.c>
	RewriteEngine On
	#RewriteBase /

	RewriteCond %{HTTP_HOST} !^www. [NC]
	RewriteRule ^(.*)$ http://www.%{SERVER_NAME}%{REQUEST_URI} [L,R=301]

	# use HTTPS
	#RewriteCond %{HTTPS} !on
	#RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
	RewriteCond %{HTTP:X-Forwarded-Proto} !=https
	RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

	# prevents files starting with dot to be viewed by browser
	RewriteRule /\.|^\.(?!well-known/) - [F]

	# front controller
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz|map)$ index.php [L]
</IfModule>

# enable gzip compression
<IfModule mod_deflate.c>
	<IfModule mod_filter.c>
		AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/json application/xml image/svg+xml
	</IfModule>
</IfModule>
zerb
Člen | 7
+
0
-

tak nakoniec sa mi to podarilo vyriesit, mozno niekomu pomoze tento kod. htaccess subor v zlozke www ostal nezmeneny a .htaccess v korenovom adresari som upravil takto:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{HTTP:X-Forwarded-Proto} !=https
    RewriteCond %{ENV:HTTPS} !^.*on
    RewriteRule ^(.*)$ https://%{SERVER_NAME}/$1 [R,L]
    RewriteRule ^$ /www/ [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /www/$1
</IfModule>
CZechBoY
Člen | 3608
+
0
-

@zerb doporučuju dát document root do složky www (kde je index.php) a ne do složky, kde jsou složky app, www, temp, log atd., nemusíš potom řešit rewrite do www a práva ve všech složkách.

pavel_l
Člen | 5
+
0
-

Zdravím.

Tato změna v Nette 2.4 mi přinesla problémy. Přesměrování na HTTPS potřebuji řešit v aplikaci, ne v .htaccess souboru. Jednak aplikace běží na větším množství domén a potom na serverech zákazníků. Také webový server do budoucna nemusí být jen Apache. Teď mám v aplikaci checkbox, kde si uživatel zvolí, jestli chce vynutit HTTPS nebo ne.

Nevidím ve 2.4 řešení, než dočasně potlačit E_USER_DEPRECATED. Myslel jsem, že bych vytvořil potomka třídy Route, ale to nejde protože proměnné objektu jsou private.

newPOPE
Člen | 648
+
0
-

Neviem o tom, ze by ta niekto nutil robit detekciu https v .htaccess-e. Ostatne vela z nas pouziva nginx pripadne proxy.

Cize si myslim, ze je mozne si https kontrolovat napr. niekde v request handleri ktory bude pocuvat na event Application.onRequest tusim.

David Grudl
Nette Core | 8118
+
0
-

Přesměrování na https se musí řešit vždy na úrovni serveru, kvůli SEO apod. Jiné řešení Nette nepodporuje.

pavel_l
Člen | 5
+
0
-

Ok, rozumím. Díky za odpověď.