Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Current »

Pro chráněné aplikace napojené na 2Element pomocí OpenID Connect existuje několik možností jak se zapojit do procesu ukončení SSO (Single Sign-On) sezení.

ID Token získaný během procesu ověření může obsahovat claim sid obsahující identifikátor SSO sezení. Chráněná aplikace by měla uložit sid anebo celý ID Token pro budoucí použití v rámci odhlášení. Pokud ID Token neobsahuje claim sid, přihlášení neproběhlo v rámci systému jednotného přihlášení (SSO) a následující metody není možné použít.

Aplikace 2Element implementuje následující OpenID specifikace:

OpenID Connect RP-Initiated Logout 1.0

URL: https://openid.net/specs/openid-connect-rpinitiated-1_0.html

Tato specifikace umožňuje chráněné aplikaci (Relying Party) požádat o ukončení SSO sezení.

Provede to přesměrováním uživatele na URL uvedené jako End Session Endpoint URI v detailu chráněné aplikace. K URL musí být přidán parametr client_id obsahující hodnotu Client ID z detailu chráněné aplikace a parametr id_token_hint obsahující ID token získaný při původním ověření uživatele. Pokud chráněná aplikace vyžaduje přesměrování uživatele zpět po provedeném odhlášení, musí přidat parametr post_logout_redirect_uri s URL na které bude uživatel po odhlášení přesměrován. Zadané URL musí být povolené v detailu chráněné aplikace, podobně jako parametr redirect_uri používaný při ověřování uživatele.

Po otevření End Session Endpoint URI v prohlížeči uživatele je zobrazen odhlašovací formulář kde uživatel musí odhlášení (ukončení SSO sezení) potvrdit. Po potvrzení dojde i k odhlášení od všech aplikací které to podporují (tj. implementují Front-Channel nebo Back-Channel Logout).

Uživatele je možné z chráněné aplikace lokálně odhlásit před přesměrováním na End Session Endpoint URI. Uživatele je také možné lokálně neodhlašovat a spoléhat na to že aplikace 2Element provede odhlášení sama pomocí mechanismů Front-Channel nebo Back-Channel Logout. Uživatel ale může ukončení SSO sezení odmítnout (ignorovat) a chráněná aplikace se o tom již nedozví.

OpenID Connect Front-Channel Logout 1.0

URL: https://openid.net/specs/openid-connect-frontchannel-1_0.html

Tato specifikace umožňuje aplikaci 2Element odhlásit uživatele z chráněné aplikace pomocí speciální odhlašovací stránky. V detailu chráněné aplikace je nutné nastavit parametr URL pro odhlášení dopředným kanálem který obsahuje stránku chráněné aplikace která při načtení uživatele odhlásí. Aplikace 2Element k tomuto URL přidá parametr iss obsahující název vydavatele a parametr sid obsahující identifikátor SSO sezení. Oba parametry jsou uvedeny jako claim v ID Tokenu získaném během procesu ověření uživatele.

Na odhlašovací stránce aplikace 2Element je pro každou chráněnou aplikaci vykreslen neviditelný rámec (iframe) se zdrojem nastaveným na hodnotu parametru URL pro odhlášení dopředným kanálem, s přidanými parametry iss a sid. Tím dojde k nahrání odhlašovací stránky v prohlížeči a následně i k odhlášení uživatele z chráněné aplikace.

Atribut SameSite v HTTP cookie

Pomocí atributu SameSame je možné v HTTP cookie omezit přístup ke cookie z jiných domén při nahrávání obsahu pomocí XHR nebo HTML značky iframe. Cílem atributu je zamezit určitému druhu XSRF (Cross-Site Scripting Forgery) útoků. Atribut může nabývat tří hodnot - None, Lax a Strict. Jedině nastavení None dovolí odesílat cookie v rámci XHR požadavků nebo z iframe při přístupu z jiných domén. Z bezpečnostních důvodů je doporučeno u session cookies nastavovat hodnotu na Lax a pokud není atribut nastaven, určí prohlížeče jako výchozí hodnotu Lax. V důsledku toho není při načítání URL pro odhlášení dopředným kanálem v iframe odeslána session cookie a chráněná aplikace tak nemá informaci o přihlášeném uživateli.

Tento problém je možné obejít nastavením atributu SameSite na None s vědomím toho že dojde ke snížení bezpečnosti. Další možností je držet informaci o uživatelském sezení kromě HTTP cookie ještě v dalším úložišti (např. v databázi) a uživatele odhlašovat jen na základě parametrů iss a sid. V tom případě ale může kdokoli se znalostí ID sezení (např. jiná chráněná aplikace) odhlásit uživatele z chráněné aplikace. Lepším řešením je implementace specifikace Back-Channel Logout.

Oproti metodě Back-Channel Logout nevyžaduje metoda Front-Channel Logout otevřený HTTP port pro přijímání odhlašovacích požadavků a je proto možné ji využít i v uzavřeném prostředí.

Více informací o atributu SameSite je např. na adrese https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite.

Blokování cookie třetích stran v prohlížečích

V současné době prohlížeče Firefox a Safari blokují nebo izolují cookie třetích stran ve snaze zamezit sledování uživatelů pomocí sledovacích cookies. U prohlížeče Chrome se předpokládá podobné chování od roku 2024. V důsledku toho není při načítání URL pro odhlášení dopředným kanálem v iframe odeslána session cookie a chráněná aplikace tak nemá informaci o přihlášeném uživateli.

Tento problém je možné obejít úpravou nastavení prohlížeče. Dalším řešením je implementace specifikace Back-Channel Logout která tímto problémem netrpí.

Více informací je možné najít např. na adresách https://support.mozilla.org/en-US/kb/introducing-total-cookie-protection-standard-mode a https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/ .

OpenID Connect Back-Channel Logout 1.0

URL: https://openid.net/specs/openid-connect-backchannel-1_0.html

Tato specifikace umožňuje aplikaci 2Element odhlásit uživatele z chráněné aplikace pomocí speciálního HTTP volání. V detailu chráněné aplikace je nutné nastavit parametr URL pro odhlášení postranním kanálem který obsahuje HTTP adresu která umožní odhlásit uživatele z chráněné aplikace. Na tuto adresu je pomocí volání POST odeslán Logout Token obsahující mimo jiné JWT claim iss a sid. Logout Token je velmi podobný ID Tokenu používaném při procesu ověření a je podepsán stejným klíčem - nesmí ale obsahovat claim nonce aby ho nebylo možné s ID Tokenem zaměnit. Po obdržení požadavku chráněná aplikace uživatele odhlásí.

Back-Channel Logout klade větší nároky na implementaci na straně chráněné aplikace protože pro držení informace o sezení nestačí session cookie. Během požadavku mezi aplikací 2Eelement a chráněnou aplikací nejsou chráněné aplikaci k dispozici HTTP cookies a tak musí informaci o sezení držet ještě v dalším úložišti (např. v databázi).

Narozdíl od Front-Channel Logout není funkčnost odhlášení omezena blokováním HTTP cookie prohlížeči a jde proto o spolehlivější metodu. Naproti tomu vyžaduje otevřený HTTP port pro přijímání odhlašovacích požadavků což může způsobovat problémy v uzavřeném prostředí.

OpenID Connect Session Management 1.0

URL: https://openid.net/specs/openid-connect-session-1_0.html

Tato specifikace umožňuje chráněné aplikaci sledovat stav sezení v rámci jednotného přihlášení (SSO) a reagovat v případě změn. Jedinou podporovanou změnou v aplikaci 2Element je zrušení platnosti SSO sezení (odhlášení).

Změna stavu sezení je sledována pomocí pravidelného zasílání zpráv chráněnou aplikací do rámce (iframe) vloženého z aplikace 2Element. Zdrojová adresa rámce je zobrazena v detailu chráněné aplikace jako Check Session IFrame URI. Pro správnou funkci CSP (Content Security Policy) hlaviček je nutné k URL přidat parametr client_id obsahující hodnotu zobrazenou jako parametr Client ID v detailu chráněné aplikace.

Zpráva vloženému rámci je text ve formátu “<client_id> <session_state>“. Parametr session_state je vrácen v odpovědi na ověření uživatele, vedle parametrů code a state (není součástí ID Tokenu).

Rámec aplikace 2Element odpovídá pomocí zprávy odeslané odesílajícímu rámci (oknu):

  • textem “unchanged” pokud je sezení stále platné

  • textem “changed” pokud už sezení není platné

  • textem “error” v případě že zaslaná zpráva nebyla ve správném formátu

V případě odpovědi “changed” může chráněná aplikace uživatele lokálně odhlásit a přesměrovat ho na přihlašovací formulář aplikace 2Element.

Rámec (nebo okno) chráněné aplikace musí u přijatých zpráv kontrolovat Origin pro zamezení Cross-Site Scripting zranitelností. Rámec aplikace 2Element kontroluje Origin pomocí hodnot zadaných jako URI pro přesměrování v detailu chráněné aplikace.

Specifikace počítá s tím že poskytovatelé identit jako je aplikace 2Element použijí pro uložení stavu o přihlášení cookies - to je ale vzhledem k blokování cookies v moderních prohlížečích často nemožné (viz. sekce o Front-Channel Logout). Implementace v aplikaci 2Element proto cookies nepoužívá a místo toho volá pomocný HTTP endpoint pro každou přijatou zprávu. Velikost dat tohoto volání je velmi malá a volání je nenáročné na výkon serveru, je proto možné ho volat poměrně často (např. každou minutu).

Specifikace počítá s použitím dvou vložených rámců - jednoho rámce chráněné aplikace a jednoho pro poskytovatele identity (aplikaci 2Element). Použití dvou rámců ve spojení s aplikací 2Element není nutné a v tuto chvíli nepřináší žádnou výhodu.

Metoda Session Management může být použita samostatně nebo kombinována s metodami Front-Channel a Back-Channel Logout. Narozdíl od ostatních metod může být také použita v SPA (Single Page Application) nebo nativních aplikacích.

Nejjednodušší možná implementace na straně webové chráněné aplikace může vypadat např. takto:

<html lang="en">
<body>

<p>session check result: <span id="result">N/A</span></p>

<script type="application/javascript">
    const PROVIDER_URL = '__PROVIDER_URL__';
    const SESSION_STATE = '__SESSION_STATE__';
    const CLIENT_ID = '__CLIENT_ID__';

    const iframe = document.createElement('iframe');

    iframe.src = `${PROVIDER_URL}/api/sso/oidc/check-session-iframe?client_id=${CLIENT_ID}`;
    iframe.style.display = 'none';

    document.body.appendChild(iframe);

    function onMessage(e) {
        if (e.origin !== PROVIDER_URL) {
            console.debug("Invalid origin: ", e.origin, " vs. ", PROVIDER_URL);

            return;
        }

        document.getElementById('result').innerText = e.data;
    }

    function checkSessionState() {
        iframe.contentWindow.postMessage(CLIENT_ID + ' ' + SESSION_STATE, PROVIDER_URL);
    }

    window.addEventListener('message', onMessage, false);

    setInterval(checkSessionState, 10 * 1000)
</script>

</body>
</html>

  • No labels