Chaves de acesso em iframes

Para oferecer uma autenticação tranquila e contextual em vários domínios, as organizações geralmente incorporam páginas de login em iframes. No entanto, carregar contextos de autenticação em frames de terceiros expõe os usuários a ameaças graves, como clickjacking (redirecionamento da interface) e criação não autorizada de credenciais. Para reduzir esses riscos, os navegadores desativam o WebAuthn em iframes de origem cruzada por padrão. Para remover essa restrição com segurança, é necessário ter protocolos ativos de defesa em profundidade.

Identificar modelos de ameaças

Antes de ativar as chaves de acesso (WebAuthn) em subframes, entenda os cenários de abuso contra os quais você está se defendendo:

  • Rastreamento usando injeção de iframe oculto:um invasor aciona uma solicitação do WebAuthn no próprio domínio usando um anúncio ou widget em um site confiável, enganando os usuários para que autorizem uma chave de acesso sem ver o contexto. Isso vincula a identidade do usuário a uma conta controlada por um invasor para coletar dados.
  • Sobreposição visual e clickjacking (redirecionamento da interface): uma página mãe maliciosa renderiza o iframe de autenticação invisível usando CSS padrão e sobrepõe um elemento de interface falso para roubar um clique que aciona um fluxo de autenticação. Isso pode resultar em sequestro de sessão ou ações não autorizadas forçadas se o usuário concluir o comando sem querer.

Para combater essas ameaças, siga estas práticas recomendadas:

Para o documento de nível superior (frame superior):

Para o documento incorporado (iframe):

Para os dois documentos:

Ativar a delegação usando a política de permissões

Por padrão, os navegadores bloqueiam o acesso à WebAuthn em iframes de origem cruzada. A política de permissões é o mecanismo unificado da plataforma da Web que permite que um documento de nível superior delegue explicitamente esses recursos avançados a origens específicas e confiáveis de terceiros.

Tokens de recursos

O WebAuthn usa dois tokens distintos:

  • publickey-credentials-get: concede autorização para fluxos de login com chaves de acesso (navigator.credentials.get()).
  • publickey-credentials-create: concede autorização para fluxos de registro de chaves de acesso (navigator.credentials.create()).

Requisitos para ativação

Para ativar esses recursos, é necessário alinhar a resposta do servidor principal e a marcação do lado do cliente:

Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")

Política de permissões: compatibilidade com publickey-credentials-get

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

Política de permissões: compatibilidade com publickey-credentials-create

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

  • O atributo HTML allow:na marcação HTML, o elemento <iframe> também precisa declarar que ativa o recurso.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Compatibilidade do iframe allow="publickey-credentials-get":

Browser Support

  • Chrome: 84.
  • Edge: 84.
  • Firefox: 118.
  • Safari: not supported.

Compatibilidade do iframe allow="publickey-credentials-create":

Browser Support

  • Chrome: not supported.
  • Edge: not supported.
  • Firefox: 123.
  • Safari: not supported.

Ativar cookies particionados de terceiros

Para garantir um fluxo de autenticação confiável, uma sessão precisa ser estabelecida e mantida no iframe incorporado de origem cruzada. À medida que os navegadores modernos passaram para restrições rígidas de cookies de terceiros, os mecanismos de persistência padrão geralmente são bloqueados por padrão e podem exigir a chamada da API Storage Access para conseguir acesso.

Para reduzir esses obstáculos, configure os cookies de sessão com os atributos SameSite: None, Secure e Partitioned. Esse mecanismo de plataforma unificada garante um estado persistente no iframe, respeitando os controles de privacidade no nível do navegador.

Definir SameSite: None

SameSite: None marca explicitamente um cookie para acesso entre sites, permitindo que ele seja enviado com solicitações feitas em um contexto de terceiros (como um iframe). Esse atributo é um pré-requisito para que os cookies funcionem em cenários de origem cruzada, mas ele precisa ser combinado com o atributo Secure para ser aceito por navegadores modernos.

Definir Partitioned

O atributo Partitioned ativa o cookie no CHIPS (Cookies com estado particionado independente), permitindo que ele seja armazenado separadamente para cada site de nível superior. Isso garante que o cookie permaneça acessível no contexto específico do iframe de terceiros, permitindo um estado de sessão persistente sem ativar o rastreamento entre sites. O usuário precisará fazer login novamente para cada incorporação em um site diferente.

Proteger o endpoint com a Política de Segurança de Conteúdo

Enquanto a Política de Permissões determina se o iframe pode executar o WebAuthn, a Política de Segurança de Conteúdo (CSP) determina quem pode hospedar o iframe.

Para um endpoint de autenticação, é fundamental garantir que apenas sites parceiros autorizados ou suas próprias propriedades possam carregar o subframe de login, encerrando tentativas não autorizadas de clickjacking antes mesmo de carregar a interface.

Usar frame-ancestors

A diretivaframe-ancestors define as páginas principais válidas que podem incorporar seu site. Ao adicionar domínios a essa diretiva, você permite que eles incorporem o subframe de login.

Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;

Política de segurança de conteúdo: compatibilidade com frame-ancestors:

Browser Support

  • Chrome: 40.
  • Edge: 15.
  • Firefox: 58.
  • Safari: 10.

Source

Definir X-Frame-Options

O cabeçalho X-Frame-Options legado oferece uma capacidade semelhante, mas só aceita opções binárias (DENY ou SAMEORIGIN). Defina frame-ancestors e X-Frame-Options: DENY da CSP caso o navegador não seja compatível com ela. A CSP é sempre priorizada onde há suporte.

X-Frame-Options: DENY

Compatibilidade com X-Frame-Options:

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 4.

Source

Confie, mas verifique do lado do servidor

As verificações do lado do cliente do navegador avaliam a intenção e as permissões, mas o servidor é o árbitro final da confiança. Verifique a resposta no servidor da parte confiante (RP) para garantir que o contexto seja válido e assinado.

Payload de dados do cliente

Os dados do cliente WebAuthn incluem parâmetros projetados especificamente para ajudar você a verificar o contexto de uma solicitação feita em um iframe:

  • crossOrigin (booleano): indica se a API WebAuthn foi invocada em um iframe de origem cruzada. Se a arquitetura depender de iframes, o servidor precisa garantir que essa flag seja true.
  • topOrigin (string): a origem do contexto de navegação de nível superior (o que é visível na barra de endereço do navegador). O servidor precisa verificar isso em uma lista de origens de familiares responsáveis conhecidas e autorizadas.

Lista de verificação da confirmação

Para verificar a resposta do autenticador no seu servidor, siga estas etapas:

  1. Analise e decodifique o collectedClientData assinado da resposta do autenticador.
  2. Verifique se o type corresponde à cerimônia (webauthn.get ou webauthn.create).
  3. Verifique a presença e a assinatura do usuário.
  4. Se a solicitação deveria vir de uma estrutura de iframe:
    • Aplicar crossOrigin === true.
    • Faça com que topOrigin corresponda à sua lista autorizada de origens principais.

Estabelecer sessões com segurança usando postMessage()

Para estabelecer uma sessão de forma confiável, o iframe precisa transmitir o token de autenticação de volta para a página mãe usando postMessage(), permitindo que ela gerencie o estado da sessão no próprio contexto.

Fluxo de trabalho seguro

Para estabelecer uma sessão segura, siga este fluxo de trabalho:

  1. Verifique se o URL do iframe src contém os parâmetros de consulta nonce e origin:
    • Use um valor aleatório para nonce. Um nonce serve como um token de verificação de segurança para garantir que o token de autenticação recebido de um iframe corresponda legitimamente à sessão específica iniciada pela página mãe.
    • Use o domínio do frame pai para o origin. Um parâmetro origin especifica a origem da página mãe, permitindo que o iframe identifique com segurança o contexto autorizado em que foi incorporado.
  2. O iframe conclui a autenticação do WebAuthn com o próprio servidor.
  3. O servidor do iframe emite um token, como um JWT, que inclui o nonce e encaminha para a página mãe.

    // Extract nonce and origin from the URL params
    const urlParams = new URLSearchParams(window.location.search);
    const nonce = urlParams.get('nonce');
    const origin = urlParams.get('origin');
    if (!nonce || !origin) {
      alert('Nonce or origin is missing in the URL');
      return;
    }
    
    // Create a JWT
    const response = await post('/createToken', { nonce, origin });
    const token = response.token;
    
    // Post the JWT to the parent frame
    window.parent.postMessage({ token }, origin);
    
  4. A página mãe detecta o evento message, valida a origem do remetente e verifica o token.

    window.addEventListener("message", (event) => {
      if (event.origin !== "https://embedded-auth.example.com") return;
      // Verify the received JWT
      const result = await post('/verifyIdToken', {
        token: event.data.token,
        origin: provider.origin,
      });
    });
    
  5. A página mãe mantém a sessão se o JWT for verificado.

O remetente e o destinatário compartilham responsabilidades de segurança:

  • O remetente (iframe): sempre especifique uma origem de destino estrita ao enviar mensagens (nunca use "*").
  • O receptor (elemento pai): sempre verifique event.origin ao receber mensagens para evitar a falsificação de origem.

Conclusão

O uso seguro de iframes depende da política de permissões para ativação, da CSP para restrição, de cookies particionados de terceiros para persistência de sessão, da verificação do lado do servidor do contexto do cliente e da transferência de sessão baseada no contexto usando postMessage().

Para saber mais sobre temas relacionados, siga o blog para desenvolvedores do Chrome do Google e confira mais recursos na documentação de identidade do desenvolvedor do Chrome.