Nette Http 3.2: změna přístupu ke credentials

před 13 dny od David Grudl  

Vyšla nová verze Nette Http 3.2, jejíž součástí je i zpětně nekompatibilní změna, ke které došlo z bezpečnostních důvodů. Týká se způsobu získání uživatelského jména a hesla při přihlašování pomocí HTTP Basic Authentication, což je nejstarší technika prováděná přímo prohlížečem.

Zatímco dříve údaje vracely metody třídy Nette\Http\Url, nyní k tomu slouží nová metoda Nette\Http\Request::getBasicCredentials():

// $request je objekt Nette\Http\Request

// dříve
$url = $request->getUrl();
$user = $url->getUser();
$password = $url->getPassword();

// od nette/http 3.2
[$user, $password] = $request->getBasicCredentials();
// $url->getUser() a $url->getPassword() nyní vrací ''

Důvod této změny je ryze bezpečnostní. Díky tomu, že jméno a heslo už nejsou součástí objektu Url, zmizelo riziko, že by při vypsání Url (tj. echo $url) došlo k jejich vyzrazení.

Přístup ke jménu a heslu skrze $request->getUrl() se v Nette používá od počátku. Jednak třída Url už příslušné metody měla, ale také v prohlížečích lze předávat uživatelské jméno a heslo přímo v adrese jako http://username:password@example.com, tedy se takové řešení nabízelo. Dnešní prohlížeče tuto funkcionalitu různými způsoby omezují, protože se začala zneužívat k nekalým účelům. Útočníci třeba lákali uživatele na adresu https://YourBank.com@HackersSite.com/, která na první pohled vypadá jako skutečná adresa banky YourBank.com, ale první část URL ve skutečnosti představuje uživatelské jméno.

Ale zpátky k Nette. Riziku vyzrazení přihlašovacích údajů předcházela přímo třída Url, která je jednoduše nevypisovala:

// Nette 2.x (a také 0.x)
$url = new Nette\Http\Url('http://user:pass@example.org');
echo $url; // http://example.org

Časem se ale objevily žádosti o změnu tohoto chování, protože pro programátory bylo překvapivé. Počínaje Nette Http 3.0 se tak credentials vypisují:

// Nette 3.x
$url = new Nette\Http\Url('http://user:pass@example.org');
echo $url; // http://user:pass@example.org

Zároveň se v presenterech místo originálního $request->getUrl() začalo pracovat s kopií bez credentials, $request->getUrl()->withoutUserInfo(). Nicméně, a to je důvod současné změny, programátoři si nemuseli být vědomi, že vypsaní originálního $request->getUrl() nese riziko vyzrazení přihlašovacích údajů. Od Nette Http 3.2 se proto credentials do objektu Url nepředávají vůbec. Tedy vypsaní $request->getUrl() je zcela bezpečné.

Místo toho se přenáší v hlavičce Authorization, jejíž obsah umí dekódovat nová metoda $request->getBasicCredentials():

// Nette Http 3.2
$request->getHeader('Authorization'); // 'Basic dXNlcjpwYXNzd29yZA=='
$request->getBasicCredentials(); // ['user', 'password']

Pokud prohlížeč přihlašovací údaje neposílá nebo se používá jiná autentizační metoda (např. Digest Access Authentication), vrací getBasicCredentials() null.