Podivné chování route:secured

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

Narazil jsem na produkčním serveru na podivné chování kolem SSL, které jsem při vývoji na localhostu nepozoroval.

Předpokládané chování (správné, ověřené na localhostu):

  • Návštěvník vidí web nešifrovaný – při přístupu na https přesměruje na http.
  • Přihlašovací formulář do administrace je šifrovaný a po přihlášení se šifruje celý web.

Chování na produkčním serveru (chybné):

  • Návštěvník může použít https, i když by nette mělo ihned přesměrovat na nešifrovanou verzi
  • při přístupu na stránku, která má SSL vynucené, se přesměrovávání zacyklí (Chyba 310(net::ERR_TOO_MANY_REDIRECTS): Proběhlo příliš mnoho přesměrování.)

V bootstrap.php mám:

<?php

// zjistime, zda je pouzito http nebo https
$flag = NULL;
if (isset($_COOKIE["ssl"])) {
    $flag = Route::SECURED;
}


// Setup router
$router = $container->router;
$router[] = new Route('index.php', 'Pages:view', Route::ONE_WAY);
$router[] = new Route('login', 'Sign:in', Route::SECURED); // login je vzdy sifrovany
// sifruje se, jen pokud je nastavena cookie "ssl",
// jinak presmerovava na nesifrovanou stranku.
$router[] = new Route('<presenter>/<action>[/<url>]', 'Pages:view',$flag);
?>

Jiný problém na produkčním serveru nemám.
Nette: 2.0-dev
PHP na produkčním serveru: 5.3.6-pl1-gentoo
PHP na localhostu: 5.3.8

Nesetkal se už někdo s podobným problémem?
Díky

zopper
Člen | 20
+
0
-

Tak jsem udělal pokus: vzal jsem sandbox, který je v distribučním archivu, a zkusil ho nahrát na hosting, zkusil jsem betu 1 (ta je použitá v projektu) i betu 2, obě verze se chovaly zcela stejně a sice tak, jak jsem popsal nahoře:

  • pokud je routa bez SECURED, mělo by dojít k přesměrování z HTTPS na HTTP, ale nedojde
  • pokud je routa se SECURED, dostanu chybu „příliš mnoho přesměrování“ – problém tedy jednoznačně musí být buď v hostingu (pravděpodobně), nebo nette.

Vyřešené to ale pořád není, bez SSL jsem v koncích.

zopper
Člen | 20
+
0
-

Tak problém identifikován, webový server všechno vidí jen http spojení (hodnoty v $_SERVER jsou nastavené na HTTP, nikoliv HTTPS bez ohledu na skutečnost) – problém je tedy jednoznačně v hostingu, možná nějaká transparentní proxy?

Existuje nějaký jiný způsob detekce HTTPS, než HTTP? Napsal jsem sice na helpdesk hostingu, ale nevím, co mi odpoví…

zopper
Člen | 20
+
0
-

Tak vyřešeno dle odpovědi z helpdesku: „vzhledem k pouziti reverzni proxy se ridte pomoci promennych X-Real-Port a X-Real-Protocol“.

Nápad: nebylo by vhodné přidat podporu pro proxy i do Nette? Takhle je potřeba řešit to dodatečně a myslím, že většina VPS to bude mít podobně.

Tohle jsem přidal na začátek bootstrap.php a nedochází k zacyklení. Sice to nepřesměruje z https na http, ale do toho se mi teď pouštět nechce.

EDIT: neuvědomil jsem si, že to i přesměrovává – funguje to tedy jak má.

<?php
// detekce https na proxy...
// port nezarucuje https, ale x-real-protocol se mi stejne tvari jako http, takze nic jineho pouzit nejde
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]) && $_SERVER["HTTP_X_REAL_PORT"] == 443){
  $_SERVER['HTTPS']="yes";
  $_SERVER['SERVER_PORT']=$_SERVER["HTTP_X_REAL_PORT"];
}

// detekce na iis - sice nemam, ale pro lepsi mit to tu, nez pak zase hledat
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
 $_SERVER['HTTPS']="yes";
}
?>

Editoval zopper (13. 1. 2012 13:44)

David Grudl
Nette Core | 8218
+
0
-

Otázka je, do jaké míry se dá spoléhat na tyto hlavičky z hlediska bezpečnosti. Protože je lze v požadavku „podvrhnout“.

net-vor
Člen | 35
+
0
-

Mám stejný problém, VPS používá reverzní proxy, pokud dám detekci $httpRequest->isSecured(), vyhodí mi to false jak v případě http, tak v případě https. Což zřejmě způsobuje, že při příznaku routy Route::SECURED dochází ke smyčce přesměrování.

Netuší někdo, co s tím, aniž bych to musel nějak hloupě obcházet nebo řešit třeba pomocí .htaccess?

n.u.r.v.
Člen | 485
+
0
-

zopper napsal(a):

Tak vyřešeno dle odpovědi z helpdesku: „vzhledem k pouziti reverzni proxy se ridte pomoci promennych X-Real-Port a X-Real-Protocol“.

Nápad: nebylo by vhodné přidat podporu pro proxy i do Nette? Takhle je potřeba řešit to dodatečně a myslím, že většina VPS to bude mít podobně.

Tohle jsem přidal na začátek bootstrap.php a nedochází k zacyklení. Sice to nepřesměruje z https na http, ale do toho se mi teď pouštět nechce.

EDIT: neuvědomil jsem si, že to i přesměrovává – funguje to tedy jak má.

<?php
// detekce https na proxy...
// port nezarucuje https, ale x-real-protocol se mi stejne tvari jako http, takze nic jineho pouzit nejde
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]) && $_SERVER["HTTP_X_REAL_PORT"] == 443){
  $_SERVER['HTTPS']="yes";
  $_SERVER['SERVER_PORT']=$_SERVER["HTTP_X_REAL_PORT"];
}

// detekce na iis - sice nemam, ale pro lepsi mit to tu, nez pak zase hledat
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
 $_SERVER['HTTPS']="yes";
}
?>

Máme stejný problém…bohužel $_SERVER[„HTTP_X_FORWARDED_FOR“] a $_SERVER[„HTTP_X_REAL_PORT“] jsou prázdné – hosting bez požádání toto neposkytuje…

Dal jsem si tedy vypsat na verzi https jaký to je port a byl to klasiky 80.

zkusil jsem tedy toto:

do bootstrap.php jsem dal natvrdo:
$_SERVER[‚HTTPS‘]=„yes“;
$_SERVER[‚SERVER_PORT‘]=‚80‘;

a do routeru ke každému jsem dal Route::SECURED…

Pak když jsem dal v browseru načíst https://projekt.cz, tak už to fungovalo. Problém je nějak zařídit aby když dá user jen verzi http://, tak aby ho to přehodilo na https…

druhý problém byl s formulářema – když jsem odeslal nějaký formulář (např. login po kterém mělo dojít k redirectu na https://projekt.cz/list, tak to přesměrovalo na https://projekt.cz:80/list – a to nejde…

Nevíte co s tím? díky

edit: potřebuji celou app v https

Editoval n.u.r.v. (6. 1. 2014 10:21)

petr.pliska
Člen | 2
+
0
-

n.u.r.v. napsal(a):

zopper napsal(a):

Tak vyřešeno dle odpovědi z helpdesku: „vzhledem k pouziti reverzni proxy se ridte pomoci promennych X-Real-Port a X-Real-Protocol“.

Nápad: nebylo by vhodné přidat podporu pro proxy i do Nette? Takhle je potřeba řešit to dodatečně a myslím, že většina VPS to bude mít podobně.

Tohle jsem přidal na začátek bootstrap.php a nedochází k zacyklení. Sice to nepřesměruje z https na http, ale do toho se mi teď pouštět nechce.

EDIT: neuvědomil jsem si, že to i přesměrovává – funguje to tedy jak má.

<?php
// detekce https na proxy...
// port nezarucuje https, ale x-real-protocol se mi stejne tvari jako http, takze nic jineho pouzit nejde
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]) && $_SERVER["HTTP_X_REAL_PORT"] == 443){
  $_SERVER['HTTPS']="yes";
  $_SERVER['SERVER_PORT']=$_SERVER["HTTP_X_REAL_PORT"];
}

// detekce na iis - sice nemam, ale pro lepsi mit to tu, nez pak zase hledat
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
 $_SERVER['HTTPS']="yes";
}
?>

Máme stejný problém…bohužel $_SERVER[„HTTP_X_FORWARDED_FOR“] a $_SERVER[„HTTP_X_REAL_PORT“] jsou prázdné – hosting bez požádání toto neposkytuje…

Dal jsem si tedy vypsat na verzi https jaký to je port a byl to klasiky 80.

zkusil jsem tedy toto:

do bootstrap.php jsem dal natvrdo:
$_SERVER[‚HTTPS‘]=„yes“;
$_SERVER[‚SERVER_PORT‘]=‚80‘;

a do routeru ke každému jsem dal Route::SECURED…

Pak když jsem dal v browseru načíst https://projekt.cz, tak už to fungovalo. Problém je nějak zařídit aby když dá user jen verzi http://, tak aby ho to přehodilo na https…

druhý problém byl s formulářema – když jsem odeslal nějaký formulář (např. login po kterém mělo dojít k redirectu na https://projekt.cz/list, tak to přesměrovalo na https://projekt.cz:80/list – a to nejde…

Nevíte co s tím? díky

edit: potřebuji celou app v https

Dobrý den, mohu se zeptat jakou máte verzi nette? Řeším teď totožný problém s formuláři pod https. Díky.

n.u.r.v.
Člen | 485
+
0
-

petr.pliska napsal(a):

n.u.r.v. napsal(a):

zopper napsal(a):

Tak vyřešeno dle odpovědi z helpdesku: „vzhledem k pouziti reverzni proxy se ridte pomoci promennych X-Real-Port a X-Real-Protocol“.

Nápad: nebylo by vhodné přidat podporu pro proxy i do Nette? Takhle je potřeba řešit to dodatečně a myslím, že většina VPS to bude mít podobně.

Tohle jsem přidal na začátek bootstrap.php a nedochází k zacyklení. Sice to nepřesměruje z https na http, ale do toho se mi teď pouštět nechce.

EDIT: neuvědomil jsem si, že to i přesměrovává – funguje to tedy jak má.

<?php
// detekce https na proxy...
// port nezarucuje https, ale x-real-protocol se mi stejne tvari jako http, takze nic jineho pouzit nejde
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]) && $_SERVER["HTTP_X_REAL_PORT"] == 443){
  $_SERVER['HTTPS']="yes";
  $_SERVER['SERVER_PORT']=$_SERVER["HTTP_X_REAL_PORT"];
}

// detekce na iis - sice nemam, ale pro lepsi mit to tu, nez pak zase hledat
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
 $_SERVER['HTTPS']="yes";
}
?>

Máme stejný problém…bohužel $_SERVER[„HTTP_X_FORWARDED_FOR“] a $_SERVER[„HTTP_X_REAL_PORT“] jsou prázdné – hosting bez požádání toto neposkytuje…

Dal jsem si tedy vypsat na verzi https jaký to je port a byl to klasiky 80.

zkusil jsem tedy toto:

do bootstrap.php jsem dal natvrdo:
$_SERVER[‚HTTPS‘]=„yes“;
$_SERVER[‚SERVER_PORT‘]=‚80‘;

a do routeru ke každému jsem dal Route::SECURED…

Pak když jsem dal v browseru načíst https://projekt.cz, tak už to fungovalo. Problém je nějak zařídit aby když dá user jen verzi http://, tak aby ho to přehodilo na https…

druhý problém byl s formulářema – když jsem odeslal nějaký formulář (např. login po kterém mělo dojít k redirectu na https://projekt.cz/list, tak to přesměrovalo na https://projekt.cz:80/list – a to nejde…

Nevíte co s tím? díky

edit: potřebuji celou app v https

Dobrý den, mohu se zeptat jakou máte verzi nette? Řeším teď totožný problém s formuláři pod https. Díky.

Mám verzi 2.1. Nakonec jsem to vyřešil tak, že jsem dal v htaccess pravidlo že celá app je https…+route:secured všude.

David Grudl
Nette Core | 8218
+
0
-

Jelikož Http\RequestFactory má podporu pro proxy, neměl by být problém to implementovat. Uděláš PR nebo issue na githubu?

petr.pliska
Člen | 2
+
0
-

n.u.r.v. napsal(a):

petr.pliska napsal(a):

n.u.r.v. napsal(a):

zopper napsal(a):

Tak vyřešeno dle odpovědi z helpdesku: „vzhledem k pouziti reverzni proxy se ridte pomoci promennych X-Real-Port a X-Real-Protocol“.

Nápad: nebylo by vhodné přidat podporu pro proxy i do Nette? Takhle je potřeba řešit to dodatečně a myslím, že většina VPS to bude mít podobně.

Tohle jsem přidal na začátek bootstrap.php a nedochází k zacyklení. Sice to nepřesměruje z https na http, ale do toho se mi teď pouštět nechce.

EDIT: neuvědomil jsem si, že to i přesměrovává – funguje to tedy jak má.

<?php
// detekce https na proxy...
// port nezarucuje https, ale x-real-protocol se mi stejne tvari jako http, takze nic jineho pouzit nejde
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]) && $_SERVER["HTTP_X_REAL_PORT"] == 443){
  $_SERVER['HTTPS']="yes";
  $_SERVER['SERVER_PORT']=$_SERVER["HTTP_X_REAL_PORT"];
}

// detekce na iis - sice nemam, ale pro lepsi mit to tu, nez pak zase hledat
if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
 $_SERVER['HTTPS']="yes";
}
?>

Máme stejný problém…bohužel $_SERVER[„HTTP_X_FORWARDED_FOR“] a $_SERVER[„HTTP_X_REAL_PORT“] jsou prázdné – hosting bez požádání toto neposkytuje…

Dal jsem si tedy vypsat na verzi https jaký to je port a byl to klasiky 80.

zkusil jsem tedy toto:

do bootstrap.php jsem dal natvrdo:
$_SERVER[‚HTTPS‘]=„yes“;
$_SERVER[‚SERVER_PORT‘]=‚80‘;

a do routeru ke každému jsem dal Route::SECURED…

Pak když jsem dal v browseru načíst https://projekt.cz, tak už to fungovalo. Problém je nějak zařídit aby když dá user jen verzi http://, tak aby ho to přehodilo na https…

druhý problém byl s formulářema – když jsem odeslal nějaký formulář (např. login po kterém mělo dojít k redirectu na https://projekt.cz/list, tak to přesměrovalo na https://projekt.cz:80/list – a to nejde…

Nevíte co s tím? díky

edit: potřebuji celou app v https

Dobrý den, mohu se zeptat jakou máte verzi nette? Řeším teď totožný problém s formuláři pod https. Díky.

Mám verzi 2.1. Nakonec jsem to vyřešil tak, že jsem dal v htaccess pravidlo že celá app je https…+route:secured všude.

Popravdě nemám moc zkušeností s Nette 2.* ale přesně tenhle problém jsme řešili na jednom projektu který používá Nette 0.9. Problém jsme vyřešili tak že jsme museli sáhnout přímo do Nette třid HttpRequest a Uri

Řešení bylo následující ve třídě HttpRequest je problém pouze v metodě isSecured(), která request testuje podle $_SERVER[‚HTTPS‘] == ‚on‘ což při requestu přes proxy není pravda a je nutné testovat podle nějaké hlavičky kde si člověk pošle protokol požadavku na proxy. Toto řeší problém secured rout.

Problém po odeslání formulářů je způsoben ve třídě Uri. kde je následující kód:

if (!$this->port && isset(self::$defaultPorts[$this->scheme])) {
	$this->port = self::$defaultPorts[$this->scheme];
}

těsně před něj jsme přidali:

if (array_key_exists('HTTP_HLAVICKA_S_PUVODNIM_PROTOKOLEM_REQUESTU', $_SERVER)) {
     $this->scheme = $_SERVER['HTTP_HLAVICKA_S_PUVODNIM_PROTOKOLEM_REQUESTU'];
}

nevím jestli je tohle ideální řešení problému ale nám to problém pomohlo vyřešit. Ještě podotýkám že máme trochu zvláštní konfiguraci Nginx(jako reverzní proxy) + Nginx s PHP-FPM jako backend. Myslím ale, že pro apache s mod PHP je to totožné.

Zkusím teda prozkoumat chování s nette 2.* a případně na to založím na issue na githubu.

Honza Kuchař
Člen | 1662
+
0
-

Pořád to nefunguje. Je v plánu, nějaké řešení?

FJP
Člen | 124
+
0
-

Ahoj ve spolek,
v posledních pár dnech jsem si díky téhle záležitosti vyrval pár vlasů :), výše uvedená řešení nezabírala.

Pes byl nakonec zakopaný ve špatném nastavení certifikátu a smyčka mohla z vesela prudit.

V prvé řade doporučuji zjistit:

  • zda si váš hosting vynucuje proxy (zjistil, jsem že to není můj případ – proto asi nefungoval hack s X-Real-Port a X-Real-Protocol)
  • zda dochází k detekci https v $_SERVER[„HTTPS“] / $_SERVER[‚SCRIPT_URI‘] – pokud ne, nakopne to adminy, aby pátrali dál na vlastní straně :)

Editoval FJP (4. 7. 2014 10:28)