O que resulta em uma boa experiência de logout?

Kenji Baheux
Kenji Baheux

Quando um usuário faz logout de um site, ele está comunicando a necessidade de sair completamente de uma experiência personalizada. Portanto, é importante aderir o mais próximo possível ao modelo mental do usuário. Por exemplo, uma experiência de encerramento de sessão adequada também precisa considerar as guias que o usuário pode ter aberto antes de decidir sair.

A chave para uma ótima experiência de encerramento de sessão é a consistência nos aspectos visuais e de estado da experiência do usuário. Este guia oferece conselhos concretos sobre o que observar e como oferecer uma boa experiência de encerramento de sessão.

Principais considerações

Ao implementar a funcionalidade de encerramento de sessão no seu site, preste atenção aos seguintes aspectos para garantir um processo tranquilo, seguro e intuitivo:

  • UX de encerramento de sessão clara e consistente: ofereça um botão ou link de encerramento de sessão claro e sempre visível, fácil de identificar e acessar em todo o site. Evite usar rótulos ambíguos ou ocultar a funcionalidade de sair em menus, subpáginas ou outros locais obscuros e não intuitivos.
  • Solicitação de confirmação: implemente uma solicitação de confirmação antes de finalizar o processo de saída. Isso ajuda a evitar que os usuários saiam da conta por engano e permite que eles reconsiderem se realmente precisam sair. Por exemplo, se eles bloquearem o dispositivo com uma senha forte ou outro mecanismo de autenticação.
  • Gerenciar várias guias: se um usuário abrir várias páginas do mesmo site em guias diferentes, verifique se o encerramento de uma guia atualiza todas as outras guias abertas desse site também.
  • Redirecione para uma página de destino segura: após sair da conta, redirecione o usuário para uma página de destino segura que indique claramente que ele não está mais conectado. Evite redirecionar os usuários para páginas com informações personalizadas. Da mesma forma, verifique se outras guias não refletem mais um estado conectado. Além disso, verifique se você não está criando um redirecionamento aberto que possa ser usado por invasores.
  • Limpeza da sessão: depois que um usuário faz logout, remova completamente todos os dados sensíveis da sessão, cookies ou arquivos temporários associados à sessão do usuário. Isso impede o acesso não autorizado a informações do usuário ou à atividade da conta e também evita que o navegador restaure páginas com informações sensíveis dos vários caches, em especial o cache de voltar/avançar.
  • Tratamento de erros e feedback: forneça mensagens de erro ou feedback claros aos usuários se houver problemas ao sair. Informe sobre possíveis riscos de segurança ou vazamentos de dados se o processo de encerramento da sessão falhar.
  • Considerações sobre acessibilidade: garanta que o mecanismo de encerramento da sessão esteja acessível a usuários com deficiência, incluindo aqueles que usam tecnologias adaptativas, como leitores de tela ou navegação por teclado.
  • Compatibilidade entre navegadores: teste a funcionalidade de encerramento da sessão em diferentes navegadores e dispositivos para garantir que ela funcione de forma consistente e confiável.
  • Monitoramento e atualizações contínuos: monitore regularmente o processo de encerramento da sessão para identificar possíveis vulnerabilidades ou falhas de segurança. Implemente atualizações e patches oportunos para resolver os problemas identificados.
  • Federação de identidade: se o usuário tiver feito login usando uma identidade federada, verifique se o encerramento da sessão do provedor de identidade também é compatível e necessário. Além disso, se o provedor de identidade oferecer suporte ao login automático, não se esqueça de impedir isso.

O que fazer

  • Se você invalidar um cookie no servidor como parte de um fluxo de encerramento da sessão (ou outros fluxos de revogação de acesso), exclua o cookie também no dispositivo do usuário.
  • Limpe todos os dados sensíveis que você possa ter armazenado no dispositivo do usuário: cookies, localStorage, sessionStorage, indexedDB, CacheStorage e qualquer outro armazenamento de dados local.
  • Verifique se todos os recursos que contêm dados sensíveis, principalmente documentos HTML, são retornados com o cabeçalho HTTP Cache-control: no-store para que o navegador não armazene esses recursos em armazenamento permanente (por exemplo, em disco). Da mesma forma, as chamadas XHR/fetch que retornam dados sensíveis também precisam definir o cabeçalho HTTP Cache-Control: no-store para evitar o armazenamento em cache.
  • Verifique se todas as guias abertas no dispositivo do usuário estão atualizadas com as revogações de acesso do lado do servidor.

Limpar dados sensíveis ao sair

Ao sair, considere limpar os dados sensíveis temporários e armazenados localmente. O foco em dados sensíveis é motivado pelo fato de que limpar tudo resultaria em uma experiência do usuário significativamente pior, porque esse usuário pode muito bem voltar. Por exemplo, se você limpar todos os dados armazenados localmente, os usuários precisarão confirmar novamente os avisos de consentimento para o uso de cookies e passar por outros processos como se nunca tivessem acessado seu site.

Como limpar cookies

Na resposta da página que confirma o status de saída, anexe cabeçalhos HTTP Set-Cookie para limpar todos os cookies relacionados a dados sensíveis ou que os contenham. Defina o valor expires como uma data em um passado distante e defina o valor do cookie como uma string vazia para garantir.

Set-Cookie: sensitivecookie1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure
Set-Cookie: sensitivecookie2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure
...

Cenário off-line

Embora a abordagem descrita acima seja suficiente para casos de uso gerais, ela não funciona se o usuário estiver trabalhando off-line. Talvez seja necessário exigir dois cookies para rastrear o estado conectado: um cookie seguro somente HTTPS e um cookie comum acessível via JavaScript. Se o usuário estiver tentando sair enquanto estiver off-line, limpe o cookie JavaScript e continue com outras operações de limpeza, se possível. Se você tiver um service worker, também poderá aproveitar a API Background Fetch para tentar novamente uma solicitação de limpeza do estado no servidor quando o usuário estiver on-line mais tarde.

Como limpar o armazenamento

Na resposta da página que confirma o estado desconectado, limpe os dados sensíveis de vários repositórios:

  • sessionStorage: embora seja limpo quando o usuário encerra a sessão no seu site, considere limpar proativamente os dados sensíveis quando o usuário sair, caso ele se esqueça de fechar todas as guias abertas no seu site.

    // Remove sensitive data from sessionStorage
    sessionStorage.removeItem('sensitiveSessionData1');
    // ...
    
    // Or if everything in sessionStorage is sensitive, clear it all
    sessionStorage.clear();
    
  • localStorage, indexedDB, Cache/APIs Service Worker: quando o usuário faz logout, limpe todos os dados sensíveis que você armazenou usando essas APIs, já que eles persistem entre as sessões.

    // Remove sensitive data from localStorage:
    localStorage.removeItem('sensitiveData1');
    // ...
    
    // Or if everything in localStorage is sensitive, clear it all:
    localStorage.clear();
    
    // Delete sensitive object stores in indexedDB:
    const name = 'exampleDB';
    const version = 1;
    const request = indexedDB.open(name, version);
    
    request.onsuccess = (event) => {
      const db = request.result;
      db.deleteObjectStore('sensitiveStore1');
      db.deleteObjectStore('sensitiveStore2');
    
      // ...
    
      db.close();
    }
    
    // Delete sensitive resources stored with the Cache API:
    caches.open('cacheV1').then((cache) => {
      await cache.delete("/personal/profile.png");
    
      // ...
    }
    
    // Or better yet, clear a cache bucket that contains sensitive resources:
    caches.delete('personalizedV1');
    

Como limpar caches

  • Cache HTTP: desde que você defina Cache-control: no-store em recursos com dados sensíveis, o cache HTTP não vai reter nada sensível.
  • Cache de volta/avançar: da mesma forma, se você seguiu as recomendações sobre Cache-control: no-store e sobre limpar cookies sensíveis (por exemplo, cookies seguros somente HTTPS relacionados à autenticação) quando os usuários fazem logout, não precisa se preocupar com a retenção de dados sensíveis no cache de volta/avançar. De fato, o recurso de cache de avanço e retorno vai remover páginas de mesma origem veiculadas com um cabeçalho HTTP Cache-control: no-store se observar um ou mais dos seguintes indicadores:
    • Um ou mais cookies seguros somente HTTPS foram modificados ou excluídos.
    • Uma ou mais respostas para XHRs/chamadas fetch emitidas pela página incluíram o cabeçalho HTTP Cache-control: no-store.

Experiência do usuário consistente em todas as guias

Os usuários podem ter aberto muitas guias do seu site antes de decidir sair. Até lá, talvez eles tenham se esquecido de outras guias ou até mesmo de outras janelas do navegador. É melhor evitar depender dos usuários para fechar todas as guias e janelas relevantes. Em vez disso, tome uma atitude proativa e garanta que o estado de login do usuário seja consistente em todas as guias.

Instruções

Para ter um estado conectado consistente em todas as guias, use uma combinação de eventos pageshow/pagehide e a API Broadcast Channel.

  • Evento pageshow: após um pageshow persistente, verifique o status de login do usuário e limpe dados sensíveis ou até mesmo toda a página se o usuário não estiver mais conectado. O evento pageshow vai acionar antes de a página ser renderizada pela primeira vez ao ser restaurada de uma navegação para frente/para trás. Assim, sua verificação de estado de login permite redefinir a página para um estado não sensível.

    window.addEventListener('pageshow', (event) => {
      if (event.persisted && !document.cookie.match(/my-cookie)) {
        // The user has logged out.
        // Force a reload, or otherwise clear sensitive information right away.
        body.innerHTML = '';
        location.reload();
      }
    });
    
  • API Broadcast Channel: use essa API para comunicar mudanças no estado de login em várias guias e janelas. Se o usuário estiver desconectado, limpe todos os dados sensíveis ou redirecione para uma página de encerramento de sessão em todas as guias e janelas com dados sensíveis.

    // Upon logout, broadcast new login state so that other tabs can clean up too:
    const bc = new BroadcastChannel('login-state');
    bc.postMessage('logged out');
    
    // [...]
    const bc = new BroadcastChannel('login-state');
    bc.onMessage = (msgevt) => {
      if (msgevt.data === 'logged out') {
        // Clean up, reload or navigate to the sign-out page.
        // ...
      }
    }
    

Conclusão

Seguindo as orientações deste documento, você poderá criar uma ótima experiência de encerramento de sessão que evita saídas não intencionais e protege as informações pessoais do usuário.