Nápad na bakalářskou práci se Spring

Re:Nápad na bakalářskou práci se Spring
« Odpověď #30 kdy: 27. 04. 2019, 14:53:57 »
Použít jen HTTPS (a z HTTP udělat jen přesměrování na HTTPS) je jen otázka konfigurace webového serveru. Autentizaci přihlášením klientským certifikátem přes HTTPS bych nedělal, podpora v prohlížečích je špatná. Ne že by to neodporovaly, ale UX je otřesné. Například Chrome vyžaduje od uživatele každých pár minut PIN k čipové kartě s uloženým certifikátem, pokud se používá TLS 1.3, protože dohodnutí nových parametrů TLS dělají opravdu důkladně až k té nové žádosti o PIN.

Pokud použijete jen jQuery, musíte si napsat sám spoustu věcí, které vám jinak poskytují ty frameworky. Angular je už dost velký framework, myslím, že by stačilo i něco lehčího – třeba Vue.js. Myslím, že se ho člověk naučí docela rychle a postará se za vás o ty dvě nejnudnější věci, které musíte pořád řešit v čistém JavaScriptu – propojení dat v JavaScriptovém objektu na HTML prvky (vstupní políčka formulářů a výstup) a spouštění akcí.

Pro autentizaci volání RESTových služeb jsem navrhoval použít protokol OAuth2, který k RESTovým požadavkům přidává JWT –JSON Web Token. V něm jsou zakódované údaje, které předal autentizační server, jsou jím podepsané a obvykle obsahují časovou značku. Autentizační server tedy vystaví JSON, ve kterém je uvedená identifikace uživatele (nějaké ID, login, e-mail apod.), může tam přidat další údaje jako třeba role uživatele a nastaví platnost tokenu třeba na 15 minut a celé to podepíše. REST server pak ověří podpis a časovou platnost toho tokenu a vytáhne si z něj potřebné údaje (např. ten login).

Hesla se na serveru nešifrují ale hashují, tj. z hashe nelze zpět získat původní heslo. Existují speciální hashovací funkce určené pro hesla, kterým tedy já osobně moc nevěřím, protože nejsou kryptograficky prověřené. Takže bych raději použil standardní SHA-256. Důležité je to, že se nehashuje samotné heslo, ale kombinace heslo+sůl+pepř. Sůl je nějaký náhodný text unikátní pro každé heslo a je uložený spolu s heslem. Pepř je také náhodný text, který ale vůbec není uložený v databázi, je někde v konfiguraci aplikace. Kdyby útočník získal databázi, nebude znát pepř a nemůže tedy zkoušet hesla hádat. Kdyby získal databázi i pepř, může zkoušet hesla hádat – zkusí nějaké heslo, k němu zná pepř i sůl, vypočítá hash a porovná ho s tím v databázi. Díky soli ale musí hádat každé heslo zvlášť. Když se nepoužije sůl ani pepř, může útočník použít tzv. duhové tabulky – tabulky, kde je ke spoustě hesel už vypočítaný hash. Pak mu stačí projít databázi a všechny uložené hashe hledat v těch duhových tabulkách. U jednoduchých hesel uspěje a získá tak hesla konkrétních uživatelů. Pokud byste chtěl o bezpečném ukládání hesel vědět víc, hodně o tom píše a přednáší Michal Špaček.

Co se týče SQL injection, takovou chybu musíte spíš pracně vyrobit – sám, nebo použitím nevhodného nástroje. SQL injection vzniká tak, že v programu skládáte ručně do textového řetězce SQL příkaz a jeho parametry. Třeba "SELECT * FROM table WHERE id = " + request.getId(). Když použijete JPA nebo Spring JDBCTemplate a parametry budete do SQL dotazů předávat pomocí mapování, SQL injection nemůže nastat (samozřejmě pokud není nějaká chyba v použitých knihovnách a nedělají to skládání řetězců interně v té knihovně).

Pro uživatelské role máte nejjednodušší použít Spring Security – poskytnete implementaci, která pro zadaného uživatele vrátí seznam jeho rolí, a pak už jenom stačí každou metodu REST controlleru označit anotací, ve které uvedete seznam rolí, které tu metodu smějí volat.


Re:Nápad na bakalářskou práci se Spring
« Odpověď #31 kdy: 28. 04. 2019, 12:39:47 »
Použít jen HTTPS (a z HTTP udělat jen přesměrování na HTTPS) je jen otázka konfigurace webového serveru. Autentizaci přihlášením klientským certifikátem přes HTTPS bych nedělal, podpora v prohlížečích je špatná. Ne že by to neodporovaly, ale UX je otřesné. Například Chrome vyžaduje od uživatele každých pár minut PIN k čipové kartě s uloženým certifikátem, pokud se používá TLS 1.3, protože dohodnutí nových parametrů TLS dělají opravdu důkladně až k té nové žádosti o PIN.

Pokud použijete jen jQuery, musíte si napsat sám spoustu věcí, které vám jinak poskytují ty frameworky. Angular je už dost velký framework, myslím, že by stačilo i něco lehčího – třeba Vue.js. Myslím, že se ho člověk naučí docela rychle a postará se za vás o ty dvě nejnudnější věci, které musíte pořád řešit v čistém JavaScriptu – propojení dat v JavaScriptovém objektu na HTML prvky (vstupní políčka formulářů a výstup) a spouštění akcí.

Pro autentizaci volání RESTových služeb jsem navrhoval použít protokol OAuth2, který k RESTovým požadavkům přidává JWT –JSON Web Token. V něm jsou zakódované údaje, které předal autentizační server, jsou jím podepsané a obvykle obsahují časovou značku. Autentizační server tedy vystaví JSON, ve kterém je uvedená identifikace uživatele (nějaké ID, login, e-mail apod.), může tam přidat další údaje jako třeba role uživatele a nastaví platnost tokenu třeba na 15 minut a celé to podepíše. REST server pak ověří podpis a časovou platnost toho tokenu a vytáhne si z něj potřebné údaje (např. ten login).

Hesla se na serveru nešifrují ale hashují, tj. z hashe nelze zpět získat původní heslo. Existují speciální hashovací funkce určené pro hesla, kterým tedy já osobně moc nevěřím, protože nejsou kryptograficky prověřené. Takže bych raději použil standardní SHA-256. Důležité je to, že se nehashuje samotné heslo, ale kombinace heslo+sůl+pepř. Sůl je nějaký náhodný text unikátní pro každé heslo a je uložený spolu s heslem. Pepř je také náhodný text, který ale vůbec není uložený v databázi, je někde v konfiguraci aplikace. Kdyby útočník získal databázi, nebude znát pepř a nemůže tedy zkoušet hesla hádat. Kdyby získal databázi i pepř, může zkoušet hesla hádat – zkusí nějaké heslo, k němu zná pepř i sůl, vypočítá hash a porovná ho s tím v databázi. Díky soli ale musí hádat každé heslo zvlášť. Když se nepoužije sůl ani pepř, může útočník použít tzv. duhové tabulky – tabulky, kde je ke spoustě hesel už vypočítaný hash. Pak mu stačí projít databázi a všechny uložené hashe hledat v těch duhových tabulkách. U jednoduchých hesel uspěje a získá tak hesla konkrétních uživatelů. Pokud byste chtěl o bezpečném ukládání hesel vědět víc, hodně o tom píše a přednáší Michal Špaček.

Co se týče SQL injection, takovou chybu musíte spíš pracně vyrobit – sám, nebo použitím nevhodného nástroje. SQL injection vzniká tak, že v programu skládáte ručně do textového řetězce SQL příkaz a jeho parametry. Třeba "SELECT * FROM table WHERE id = " + request.getId(). Když použijete JPA nebo Spring JDBCTemplate a parametry budete do SQL dotazů předávat pomocí mapování, SQL injection nemůže nastat (samozřejmě pokud není nějaká chyba v použitých knihovnách a nedělají to skládání řetězců interně v té knihovně).

Pro uživatelské role máte nejjednodušší použít Spring Security – poskytnete implementaci, která pro zadaného uživatele vrátí seznam jeho rolí, a pak už jenom stačí každou metodu REST controlleru označit anotací, ve které uvedete seznam rolí, které tu metodu smějí volat.

Děkuji.
Jednu věc nechápu. Bavíme se o autentizaci přes OAuth2 a k tomu by měl být i možný způsob autentizaci i normální, že? Jakože klasická registrace na straně té aplikace.
Řekněme, že se uživatel přihlásí přes FB. Jak to ted bude reálně fungovat? Řekněme, že tam bude prostě úvodní stránka, kde se danému člověku budou vypisovat nové události ze všech společenstev, ve kterých je členem.
Čili by byl dotaz na DB - "neco... WHERE user.id = X;" - nicméně když se přihlásí přes FB, tak jak tohle zjistím, když toho člověka vlastně fyzicky v databázi nemám, ne? Tak jak zjistím, do jakých společenstev se přidal, na jakých bude akcích atd, když ho fyzicky v databazi mít nebudu?

Re:Nápad na bakalářskou práci se Spring
« Odpověď #32 kdy: 28. 04. 2019, 12:43:59 »
Jo a ještě jedna věc...
U Rest Api jsem koukal, že je anotace @Secured(role) - jakým způsobem se přenáší ta role mezi springem a front endem? Uložená v jsonu nějak?

Re:Nápad na bakalářskou práci se Spring
« Odpověď #33 kdy: 28. 04. 2019, 13:38:41 »
Autentizace říká, kdo je přihlášený uživatel. Způsobů autentizace můžete mít několik vedle sebe. Jeden asi bude jménem a heslem – uživatel zadá na formuláři jméno a heslo, vy ho podle jména v databázi vyhledáte a ověříte heslo. Když použijete přihlašování přes třetí stranu (např. Facebook), při registraci si opět uložíte údaje o uživateli do databáze, pak ho necháte přihlásit se přes Facebook a Facebook vám vrátí nějaký (pro Facebook) unikátní identifikátor toho uživatele. A ten vy si uložíte k tomu uživatelskému profilu do databáze. Když se příště přihlásí přes Facebooku, Facebook vám zase vrátí to samé ID a podle toho vy si v databázi najdete, který je to uživatel. Takže v databázi budete mít nejspíš nějakou tabulku s uživatelským profilem (třeba jeho jméno, příjmení a e-mail), vedle toho jinou tabulku se jménem a heslem a další tabulku s ID z Facebooku. A k jednomu profilu můžete mít uložený jak záznam v tabulce se jménem a heslem, tak záznam v tabulce Facebooku – uživatel si pak může vybrat, kterou variantou se přihlásí.

HTTP je ale bezstavový protokol, tedy normálně by uživatel musel zadávat své jméno a heslo (nebo se přihlašovat přes Facebook) s každým požadavkem, který se pošle na server. To samozřejmě nikdo dělat nebude – místo toho server uživatele ověří jednou a na základě toho předá klientovi nějakou informaci, kterou pak klient posílá s každým dalším požadavkem. A podle ní server pozná, že jde o toho přihlášeného klienta. Dříve se to dělalo tak, že server přidělil přihlášenému uživateli nějaké unikátní číslo (nazývané třeba session ID), a někam si poznamenal, že tohle session ID je uživatel třeba Franta Novák. Pak session ID poslal klientovi a ten ho přidával jako cookie do každého dalšího požadavku na server. Server si podle toho session ID z cookie dohledal příslušný záznam a z něj si přečetl, že s tímhle session ID je přihlášený uživatel Franta Novák. To má tu nevýhodu, že musí být na serveru to úložiště session ID, takže můžete mít jenom jeden server, nebo – když jich máte víc – potřebujete mezi nimi sdílet to úložiště session ID.

A tady do toho vstupuje ten OAuth2 protokol. Místo toho, aby si server poznamenával session ID, tak vytvoří elektronický dokument (ve formátu JSON), který říká „přihlášený uživatel je Franta Novák“, a případně k tomu doplní další údaje. A tenhle dokument elektronicky podepíše a pak ho i s tím podpisem předá klientovi. Klient pak ke každému požadavku nepřidává session ID, ale tenhle elektronicky podepsaný dokument, kterému se říká (autentizační) token (ve skutečnosti je velmi krátký, desítky znaků). Když ho dostane server, ověří ten podpis, a pokud sedí, ví, že může důvěřovat té informaci „přihlášený uživatel je Franta Novák“. Tím pádem si server nemusí pamatovat žádné session ID, ale i když budete mít 80 serverů po celém světě, pokud bude každý z nich umět ověřit ten elektronický podpis, dokáže bezpečně zjistit, že jde o toho správného uživatele.

Ve vašem případě je pro tu autentizaci REST požadavků OAuth2 trochu kanón na vrabce, ale je to průmyslový standard, se kterým umí zacházet spousta knihoven a frameworků. A Spring už má podporu v sobě, takže nemusíte nic implementovat, jenom to nakonfigurujete. V dokumentaci Springu Spring Security Reference jsou ty varianty použití OAuth2 popsané.

Druhá věc je, že OAuth2 se používá i přitom přihlašování třeba přes Facebook, ale to s tou autentizace REST požadavků nesouvisí. Vlastně byste tam měl OAuth2 použité na dvou nesouvisejících místech – pro přihlášení přes Facebook a pro autentizaci REST požadavků.

Aby vám fungovala anotace @Secured(role), musíte implementovat rozhraní UserDetailsService, kde je metoda, která vrací uživatele a jeho role. Ve vašem případě je nejjednodušší podle předaného identifikátoru si uživatele dohledat v databázi a z ní načíst i odpovídající role.

S OAuth2 by se to dalo udělat i tak, že se ty role načtou při přihlášení uživatele a přidají se do toho autentizačního tokenu, který se pak posílá s každým požadavkem. Díky tomu podpisu pak server ví, že tomu seznamu rolí může důvěřovat. To se ale používá spíš v případech, kdy máte oddělený server, který dělá autentizaci, a server, který poskytuje vlastní služby. Ten server pak nemusí vědět nic o uživatelích, prostě se jenom řídí tím, co je v tom tokenu.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #34 kdy: 28. 04. 2019, 14:38:41 »
Mockrát Vám děkuji. Ta Vaše vysvětlení jsou pro mě (jako člověka, co s tím nikdy nepracoval) velmi pochopitelná. Čili navrhujete: Aby REST api bylo zabezpečené přes Oauth2 - tím způsobem, jak jste popisoval. Čili na serveru se vytvoří nějaký elektronický dokument podepsaný, který pošle na klienta a ověřuje ho podle podpisu. A FB/Google přihlášení byste do toho nedoporučoval? Že jste psal, že se bude míchat Oauth2 na dvou nesouvislých místech? A pokud by se mi podařilo do té aplikace toto implementovat + to hashování hesla + ty role, tak by to dle Vás bylo bezpečnostně v pořádku? Samozřejmě ještě nevím, co s tím https potom...


Re:Nápad na bakalářskou práci se Spring
« Odpověď #35 kdy: 29. 04. 2019, 09:32:21 »
Mockrát Vám děkuji. Ta Vaše vysvětlení jsou pro mě (jako člověka, co s tím nikdy nepracoval) velmi pochopitelná.
Děkuji. Pro mne je to důležitá informace, že to vysvětlování má smysl a že to je srozumitelné. Abych si tu jen tak nepsal něco, čemu z 90 % nebude rozumět :-)

Čili navrhujete: Aby REST api bylo zabezpečené přes Oauth2 - tím způsobem, jak jste popisoval. Čili na serveru se vytvoří nějaký elektronický dokument podepsaný, který pošle na klienta a ověřuje ho podle podpisu.
Ano. Ten dokument, který se používá v OAuth2 protokolu, se nazývá JWT – JSON Web Token. Jeho generování a ověřování nebudete implementovat, ve Springu už jsou knihovny, které to implementují. Vy to musíte jen nakonfigurovat (jaké klíče se mají použít apod.) a implementovat věci, na kterých to generování a ověřování závisí. Např. když se uživatel přihlásí jménem a heslem, Spring zavolá vaší službu, které předá to jméno a heslo, vy implementujete vyhledání uživatele v databázi, ověření hesla a zjištění dalších údajů o uživateli (třeba jeho plné jméno a role) a tyhle údaje vrátí vaše služba Springu, a ten už z toho ten JWT vyrobí.

A FB/Google přihlášení byste do toho nedoporučoval? Že jste psal, že se bude míchat Oauth2 na dvou nesouvislých místech?
Že se to bude míchat na dvou místech bylo myšleno tak, aby vás nemátlo, že se ten protokol může v té aplikaci použít dvěma způsoby, které spolu nijak nesouvisí. Je spoust aplikací, které používají OAuth2 pro zabezpečení svých REST služeb, a přihlášení přes FB  nebo Google neimplementují. A naopak je spousta aplikací, které implementují přihlášení přes FB nebo Google, ale jiným způsobem OAuth2 nepoužívají.

Já osobně bych doporučoval v takové aplikaci mít implementované přihlášení minimálně přes FB, Google, MojeID a asi i Twitter, protože zejména u aplikací, které používám jen občas, je otravné přihlašovat se jménem a heslem. A to používám správce hesel, takže pro mne je to přihlášení jednodušší, než pro většinu lidí, kteří si musí nějaké heslo vymyslet a pak si ho pamatovat. Ale to přihlášení přes systémy třetích stran je volitelná funkce, dá se doplnit kdykoli později – spíš je to další funkce, kterou můžete přidat, když se budete chtít naučit něco dalšího.

A pokud by se mi podařilo do té aplikace toto implementovat + to hashování hesla + ty role, tak by to dle Vás bylo bezpečnostně v pořádku? Samozřejmě ještě nevím, co s tím https potom...
Z hlediska autentizace by to mělo být v pořádku, protokoly, o kterých se bavíme, jsou prověřené, implementace použitá ve Springu pokud vím nemá žádné známé bezpečnostní problémy. Jinak je ale potřeba bezpečnost řešit u každé části aplikace, nedá se říct, že by aplikace použitím nějaké technologie byla bezpečná. Vždy musíte počítat např. s tím, že uživatel v prohlížeči sice může zadat např. jen číslo, ale schopnější uživatel si umí z prohlížeče ten JWT vytáhnout a zavolá tu vaší RESTovou službu jinak, a místo čísla tam dá text nebo ho nevyplní vůbec. Aplikace v takovém případě má vypsat chybu ale hlavně nesmí udělat žádnou operaci, na kterou uživatel nemá oprávnění.

Aplikace ve Springu se myslím většinou nevystavují přímo do internetu – obvykle tam bývá předřazený proxy server (třeba Nginx). Na tom předřazeném serveru se nakonfiguruje HTTPS (a přesměrování z HTTP na HTTPS), ten proxy server pak už může komunikovat se Springovou aplikací nešifrovaným HTTP – běží buď na stejném serveru nebo ve stejné síti. A i kdyby ta Springová aplikace měla (sama) běžet přes HTTPS, je to jen otázka konfigurace, té aplikace se to nijak nedotkne. Ve frontendové části aplikace se HTTPS vyřeší ještě snadněji, tam jde jenom o to v URL pro volání RESTových služeb použít protokol https a ne http. A samozřejmě je potřeba i tu frontendovou aplikaci servírovat ze serveru přes HTTPS – u malé aplikace to může dělat ten samý server, který dělá proxy server té backendové Springové aplikaci. Tj. pak máte třeba Nginx server, na něm je nakonfigurované HTTPS a s tím serverem komunikuje webový prohlížeč. Ten Nginx jednak poskytuje (statické) soubory frontendové aplikace, a jednak určité URL (třeba https://example.com/api/*) přeposílá na tu backendovou aplikaci ve Springu.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #36 kdy: 10. 05. 2019, 12:12:24 »
Mockrát Vám děkuji. Ta Vaše vysvětlení jsou pro mě (jako člověka, co s tím nikdy nepracoval) velmi pochopitelná.
Děkuji. Pro mne je to důležitá informace, že to vysvětlování má smysl a že to je srozumitelné. Abych si tu jen tak nepsal něco, čemu z 90 % nebude rozumět :-)

Čili navrhujete: Aby REST api bylo zabezpečené přes Oauth2 - tím způsobem, jak jste popisoval. Čili na serveru se vytvoří nějaký elektronický dokument podepsaný, který pošle na klienta a ověřuje ho podle podpisu.
Ano. Ten dokument, který se používá v OAuth2 protokolu, se nazývá JWT – JSON Web Token. Jeho generování a ověřování nebudete implementovat, ve Springu už jsou knihovny, které to implementují. Vy to musíte jen nakonfigurovat (jaké klíče se mají použít apod.) a implementovat věci, na kterých to generování a ověřování závisí. Např. když se uživatel přihlásí jménem a heslem, Spring zavolá vaší službu, které předá to jméno a heslo, vy implementujete vyhledání uživatele v databázi, ověření hesla a zjištění dalších údajů o uživateli (třeba jeho plné jméno a role) a tyhle údaje vrátí vaše služba Springu, a ten už z toho ten JWT vyrobí.

A FB/Google přihlášení byste do toho nedoporučoval? Že jste psal, že se bude míchat Oauth2 na dvou nesouvislých místech?
Že se to bude míchat na dvou místech bylo myšleno tak, aby vás nemátlo, že se ten protokol může v té aplikaci použít dvěma způsoby, které spolu nijak nesouvisí. Je spoust aplikací, které používají OAuth2 pro zabezpečení svých REST služeb, a přihlášení přes FB  nebo Google neimplementují. A naopak je spousta aplikací, které implementují přihlášení přes FB nebo Google, ale jiným způsobem OAuth2 nepoužívají.

Já osobně bych doporučoval v takové aplikaci mít implementované přihlášení minimálně přes FB, Google, MojeID a asi i Twitter, protože zejména u aplikací, které používám jen občas, je otravné přihlašovat se jménem a heslem. A to používám správce hesel, takže pro mne je to přihlášení jednodušší, než pro většinu lidí, kteří si musí nějaké heslo vymyslet a pak si ho pamatovat. Ale to přihlášení přes systémy třetích stran je volitelná funkce, dá se doplnit kdykoli později – spíš je to další funkce, kterou můžete přidat, když se budete chtít naučit něco dalšího.

A pokud by se mi podařilo do té aplikace toto implementovat + to hashování hesla + ty role, tak by to dle Vás bylo bezpečnostně v pořádku? Samozřejmě ještě nevím, co s tím https potom...
Z hlediska autentizace by to mělo být v pořádku, protokoly, o kterých se bavíme, jsou prověřené, implementace použitá ve Springu pokud vím nemá žádné známé bezpečnostní problémy. Jinak je ale potřeba bezpečnost řešit u každé části aplikace, nedá se říct, že by aplikace použitím nějaké technologie byla bezpečná. Vždy musíte počítat např. s tím, že uživatel v prohlížeči sice může zadat např. jen číslo, ale schopnější uživatel si umí z prohlížeče ten JWT vytáhnout a zavolá tu vaší RESTovou službu jinak, a místo čísla tam dá text nebo ho nevyplní vůbec. Aplikace v takovém případě má vypsat chybu ale hlavně nesmí udělat žádnou operaci, na kterou uživatel nemá oprávnění.

Aplikace ve Springu se myslím většinou nevystavují přímo do internetu – obvykle tam bývá předřazený proxy server (třeba Nginx). Na tom předřazeném serveru se nakonfiguruje HTTPS (a přesměrování z HTTP na HTTPS), ten proxy server pak už může komunikovat se Springovou aplikací nešifrovaným HTTP – běží buď na stejném serveru nebo ve stejné síti. A i kdyby ta Springová aplikace měla (sama) běžet přes HTTPS, je to jen otázka konfigurace, té aplikace se to nijak nedotkne. Ve frontendové části aplikace se HTTPS vyřeší ještě snadněji, tam jde jenom o to v URL pro volání RESTových služeb použít protokol https a ne http. A samozřejmě je potřeba i tu frontendovou aplikaci servírovat ze serveru přes HTTPS – u malé aplikace to může dělat ten samý server, který dělá proxy server té backendové Springové aplikaci. Tj. pak máte třeba Nginx server, na něm je nakonfigurované HTTPS a s tím serverem komunikuje webový prohlížeč. Ten Nginx jednak poskytuje (statické) soubory frontendové aplikace, a jednak určité URL (třeba https://example.com/api/*) přeposílá na tu backendovou aplikaci ve Springu.

Zdravím,
a jak to ještě funguje s CSRF? Řekněme, že bych použil Oauth2 k zabezpečení těch REST služeb. CSRF hrozí? Případně mu předpokládám je vhodné nějakým způsobem zamezit?

Děkuji

Re:Nápad na bakalářskou práci se Spring
« Odpověď #37 kdy: 10. 05. 2019, 19:53:47 »
a jak to ještě funguje s CSRF? Řekněme, že bych použil Oauth2 k zabezpečení těch REST služeb. CSRF hrozí? Případně mu předpokládám je vhodné nějakým způsobem zamezit?
CSRF spočívá v tom, že v okamžiku, kdy je uživatel přihlášen do aplikace, přinutíte prohlížeč, aby poslal platný požadavek včetně autentizačních údajů. To funguje například tehdy, když je přihlášený uživatel identifikován pomocí cookie – prohlížeč ji přibalí automaticky k požadavku, i když byl požadavek odeslán z jiné webové stránky. Při použití OAuth2 se ale autentizační token obvykle posílá v hlavičce Authorization a o jeho přiložení se musí postarat ten kód, který tu RESTovou službu volá – tj. nedělá to prohlížeč automaticky. Tedy případný útočník by musel autentizační token také připojit k požadavku ručně – ale to by jej nejprve musel získat. Pokud bude uložený např. jen v JavaScriptové aplikaci na klientovi, tak token získat nemůže (pokud v té aplikaci není speciální kód, který by to umožnil). Případně může být ten token uložen v Session Storage nebo Local Storage – ty jsou vázané na doménu, takže útočící skript z jiné domény se k nim nedostane. Nicméně pokud by pod jednou doménou běželo několik aplikací, ty už by si mohly navzájem číst Session Storage nebo Local Storage. Ale pokud poběží víc aplikací pod jednou doménou, těch způsobů, jak se navzájem ovlivnit, je mnoho – takže bych buď počítal s tím, že na dané doméně bude aplikace samotná, a nebo tam budou jen důvěryhodné aplikace.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #38 kdy: 11. 05. 2019, 00:02:24 »
Děkuji.
Čili za předpokladu, že budu používat Oauth2 pro ty rest api, budu mít aplikaci, kdy bude jeden server a jakože "jeden" front end, tak k CSRF nemůže dojít, pokud ten token bude prostě uložený někde v JS kodu na klientovi. Je to takto správně? Já jsem
A existují nějaké útoky přímo na ten Oauth2, na který bych si měl dát pozor?

Re:Nápad na bakalářskou práci se Spring
« Odpověď #39 kdy: 11. 05. 2019, 08:59:53 »
Ano, pokud ten token bude uložen v JS aplikaci na frontendu, z pohledu CSRF je to bezpečné – útočník se k tokenu nemůže dostat a prohlížeč ho neposílá automaticky, tj. požadavek s validním tokenem nemůže odejít jinak, než přímo z vaší aplikace.

Pokud se OAuth2 implementuje podle aktuálních doporučení, žádný známý útok mne nenapadá. Jedině to, že u Single Page Aplikací (SPA) se dříve doporučovalo u autentizace přes OAuth2 implicit flow, dnes už se doporučuje provést i v tomhle případě standardní získání tokenu. Celý proces přihlášení přes OAuth2 je odbře popsán teřba v OAuth 2 Simplified a jsou tam i odkazy na aktuální doporučení.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #40 kdy: 02. 07. 2019, 11:00:12 »
Ano, pokud ten token bude uložen v JS aplikaci na frontendu, z pohledu CSRF je to bezpečné – útočník se k tokenu nemůže dostat a prohlížeč ho neposílá automaticky, tj. požadavek s validním tokenem nemůže odejít jinak, než přímo z vaší aplikace.

Pokud se OAuth2 implementuje podle aktuálních doporučení, žádný známý útok mne nenapadá. Jedině to, že u Single Page Aplikací (SPA) se dříve doporučovalo u autentizace přes OAuth2 implicit flow, dnes už se doporučuje provést i v tomhle případě standardní získání tokenu. Celý proces přihlášení přes OAuth2 je odbře popsán teřba v OAuth 2 Simplified a jsou tam i odkazy na aktuální doporučení.

Zdravím,
tak se do toho pomalu pouštím, včera jsem začal studoval Oauth2 a začal trošku i to programovat. Nicméně motá mi hlavu toto...
1) Dočetl jsem se, že má být client id a client secret. A to má být oboje nějak zašifrovaný. Proč?
2) Povedlo se mi udělat, že jsem si vygeneroval certifikát a podepsal na autorizačním serveru privátním klíčem, public klíčem jsem to rozšifroval - ALE... Mám používat cliend id s client secret nebo to podepisování? A nebo oboje? Případně proč?
3) Chtěl bych ještě docílit toho, že se vypočte u těch JWT, zda ten JWT nebyl nějak změněn. Dá se toho nějak docílit?

Ta bakalářka jinak bude o něčem jiném, tamto téma mi neprošlo (neschválilo mi to vedení), takže se to muselo hodit spíše do bezpečnosti.
Případně, mohl bych se Vám takhle někdy zase ozvat, kdybych v něčem byl zaseknutý?

Mockrát děkuji
Mohl bych Vás

Re:Nápad na bakalářskou práci se Spring
« Odpověď #41 kdy: 02. 07. 2019, 13:30:53 »
Client-id je veřejný údaj, ten není potřeba šifrovat. Client secret se používá v případě, kdy se autentizuje serverová aplikace, do které můžete ten klíč client secret schovat. Pokud se autentizuje webová aplikace běžící v prohlížeči, client secret se nepoužívá – bezpečnost je založená na tom, že autentizační server po dokončení autentizace přesměruje prohlížeč na adresu, která je svázaná s daným klientem. Tj. i kdyby přihlášení zahájil útočník, skončí to tak, že se uživatel přihlásí do té správné (ne útočníkovi) aplikace.

Pro podpis JWT se pak mohou použít dvě různé metody – buď  se používá sdílený klíč, nebo klasický elektronický podpis s veřejným a privátním klíčem. Ten sdílený klíč se používá v případě, kdy si aplikace navzájem důvěřují a vše je na serveru, takže se sdílený klíč k nikomu cizímu nedostane. Aplikace, která JWT token jenom ověřuje, totiž musí mít ten samý klíč, který se používá pro vytvoření podpisu – škodlivá aplikace by tudíž mohla sama vytvořit falešný JWT, který by ale byl podepsán tím správným klíčem, a třetí aplikace by mu důvěřovala.

Druhá možnost je použití veřejného a privátního klíče. To používají třeba veřejné služby – když se přihlašujete prostřednictvím Google nebo Twitteru, dají vám jenom veřejný klíč. Nemohou použít přístup se sdíleným klíčem, protože pak by tím jejich klíčem mohl kdokoli podepsat JWT, který by pak vypadal jako skutečný JWT od Googlu nebo Twitteru. Implementačně je ten způsob s dvojicí klíčů trochu složitější, ale většinou používáte nějakou knihovnu, kde už je to podepisování zapouzdřené a vy to nemusíte řešit. Pokud tedy klienta nemáte pod kontrolou (buď je to webová aplikace v prohlížeči, a nebo aplikace třetích stran), používá se tahle druhá metoda s veřejným i privátním klíčem. My to například budeme používat i v jednom spolku, kde se bude autentizovat víc různých aplikací. Sice jsou všechny ty aplikace „naše“ a mohli bychom jim věřit, ale očekáváme, že i ty „naše“ aplikace budou různě důvěryhodné – takže rovnou použijeme tu variantu s veřejným a privátním klíčem, a ten privátní klíč bude znát jenom aplikace provádějící autentizaci.

Kontrola toho, zda JWT nebylo změněno, by se měla provádět vždy, když se JWT použije (budete z něj číst nějaká data). K tomu právě slouží ten podpis. V knihovnách to obvykle bývá nazváno jako validace a ověří se právě to, že podpis sedí s daty, tj.  po podepsání nedošlo ke změně dat. K validaci je právě potřeba znát buď ten sdílený klíč nebo veřejný klíč, podle toho, co se používá.


Mám na tohle diskusní téma zapnuté e-mailové notifikace, takže když sem vložíte příspěvek, dozvím se to, a pokusím se poradit, pokud budu vědět.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #42 kdy: 02. 07. 2019, 19:21:34 »
Přemýšlím, jakým způsobem to udělat na front endu s oauthem2.
1.) Potřeboval bych login a po úspěšném loginu jako být na jiné stránce (index.html) třeba. Čili nápad by byl, že když dostane klient ten access_token, tak se přes JS udělá redirect na ten index.html. Ale řeknemě, že ten login bude první stránka, která se má objevit - třeba mojestranka.cz/login.html - Jak ale zamezím tomu, že si tam uživatel třeba napíše mojestranka.cz/index.html a dostane se na tu indexovou stránku i bez toho tokenu?

2.) Řekněme, že ten token je elektronicky podepsanej. Na klientskou část aplikace bych nahrál public klíč. Jak to potom na té front endové části přeložím do nějaké čitelné formy pro mě?

Děkuji

Re:Nápad na bakalářskou práci se Spring
« Odpověď #43 kdy: 03. 07. 2019, 08:20:29 »
Každá stránka by si měla kontrolovat, zda je token k dispozici – a pokud není, přesměrovat uživatele na přihlašovací stránku.

JWT je jen JSON zakódovaný v BASE64 (resp. jsou to tři objekty, každý se zakóduje do BASE64 a vše se pak spojí tečkou do jednoho řetězce). Takže získat z toho ty údaje (pokud byste neprováděl validaci) jde i ručně. Lepší je ale použít hotovou knihovnu, např. na jwt.io je docela dobrý přehled knihoven pro různé jazyky.

Re:Nápad na bakalářskou práci se Spring
« Odpověď #44 kdy: 03. 07. 2019, 21:44:52 »
Narazil jsem dneska na problém při AJAxu z front endu. Nemohu dostat ten access token, když mám server na localhostu evidentně... hlási mi to CORS...
Nakonec jsem to částečně vyřešil tímto requestem pomocí jQuery.

Kód: [Vybrat]
$.ajax({
        url: 'http://localhost:8080/oauth/token',
        "async": true,
        crossDomain: true,
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json; charset=UTF-8',
        headers: {"Authorization": "Basic bXktY2xpZW50Om15LXNlY3JldA==", "Content-Type": "application/x-www-form-urlencoded"},
        data: {
            "password": "George",
            "username": "pleb@seznam.cz",
            "grant_type": "password"
          },

        complete: function(result) {
            alert(result + " COMPLETE ");
        },

        success: function(result) {
            alert(result + " OK!");
        },

        error: function(result) {
            alert(result + " CHYBA");
        },
    });
    return true;
}

Nicméně aby to fungovalo, tak jsem musel ještě udělat tuto třídu na straně serveru

Kód: [Vybrat]
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsConfig implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Alow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age","3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type");

        if("OPTIONS".equalsIgnoreCase(request.getMethod())){
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }


    @Override
    public void destroy() {

    }
}


Což je zřejmě nebezpečné takto to ponechat, že? Napadlo by Vás nějaké řešení, jak tohle vyřešit? Abych se dostal k tomu oauth2 tokenu bez toho, abych musel dělat ten filtr?